Generic SmartCore functionality.
gem'smart_engine'bundle install
# --- or ---
gem install smart_enginerequire'smart_core'- Global set of error types
- Simple reentrant lock
- Read/Write Lock
- Cache Storage
- Atomic thread-safe value container
- Any Object Frozener (classic c-level
frozen?/freeze) - Basic Object Refinements (
SmartCore::Ext::BasicObjectAsObject) - Inline rescue pipe
SmartCore::Error(inherited from::StandardError);SmartCore::ArgumentError(inherited from::ArgumentError);SmartCore::FrozenError(inherited from::FrozenError);SmartCore::NameError(inherited from::NameError);SmartCore::TypeError(inherited from::TypeError);
lock=SmartCore::Engine::Lock.newlock.synchronize{your_code}- non-controlable reader count;
- readers does not lock each other;
- readers waits for writer;
- writer waits for readers;
lock=SmartCore::Engine::ReadWriteLock.newlock.read_sync{ ...some-read-op... }# waits for writerlock.read_sync{ ...some-read-op... }# waits for writerlock.write_sync{ ... some-write-op... }# waits for all readers and current writer# is write_sync lock is owned by current thread?lock.write_owned?# true or falseyou can use any object as a cache key;
you can store any object as a cache value;
you can cache
nilobject too;cache
readhasfetchsemantics:- signature:
#read(key, &fallback); - in the event of cache miss the
&fallbackblack will be invoked; - the return value of the fallback block will be written to the cache, and that return value will be returned;
- signature:
cache
write:- signature:
#write(key, value); - you can use any object as a cache key;
- you can store any object as a value;
- you can write
nilobject too;
- signature:
cache clear:
- signature:
#clear;
- signature:
cache=SmartCore::Engine::Cache.new# write and readcache.write(:amount,123.456)# => 123.456cache.read(:amount)# => 123.456# read non-existing with a fallbackcache.read('name')# => nilcache.read('name'){'D@iVeR'}# => 'D@iVeR'cache.read('name')# => 'D@iVeR'# store nil objectcache.write(:nil_value,nil)# => nilcache.read(:nil_value)# => nilcache.read(:nil_value){'rewritten'}# => nilcache.read(:nil_value)# => nil# clear cachecache.clear# => nil# aliases:# write:cache[:key1]='test'# read:cache[:key1]# => 'test'# read with fallback:cache[:key2]{'test2'}# => 'test2'cache[:key2]# => 'test2'atom=SmartCore::Engine::Atom.new# initial value - nilatom.value# => nil# --- or ---atom=SmartCore::Engine::Atom.new(7)# initial value - 7atom.value# => 7# set new value (thread-safely)atom.swap{ |original_value| original_value * 2}atom.value# => 14- works with any type of ruby objects (event with
BasicObject); - uses classic Ruby C-level
frozen?/freezefunctionality;
# as a singletonobject=BasicObject.newSmartCore::Engine::Frozener.frozen?(object)# => falseSmartCore::Engine::Frozener.freeze(object)SmartCore::Engine::Frozener.frozen?(object)# => true# as a mixinclassEmptyObject < BasicObjectincludeSmartCore::Engine::Frozener::Mixinendobject=EmptyObject.newobject.frozen?# => falseobject.freezeobject.frozen?# => trueRuby's BasicObject class does not have some fundamental (extremely important for instrumenting) methods:
is_a?/kind_of?instance_of?freeze/frozen?hashnil?inspect
SmartCore::Ext::BasicObjectAsObject refinement solves this problem (by Ruby's internal API without any manualy-emulated behavior).
# without refinement:basic_obj= ::BasicObject.newbasic_obj.is_a?(::BasicObject)# raises ::NoMethodErrorbasic_obj.kind_of?(::BasicObject)# raises ::NoMethodErrorbasic_obj.instance_of?(::BasicObject)# rasies ::NoMethodErrorbasic_obj.freeze# raises ::NoMethodErrorbasic_obj.frozen?# raises ::NoMethodErrorbasic_object.hash# raises ::NoMethodErrorbasic_object.nil?# raises ::NoMethodErrorbasic_object.inspect# raises ::NoMethodError# with refinement:usingSmartCore::Ext::BasicObjectAsObjectbasic_obj= ::BasicObject.newbasic_obj.is_a?(::BasicObject)# => truebasic_obj.kind_of?(::BasicObject)# => truebasic_obj.instance_of?(::BasicObject)# => truebasic_obj.instance_of?(::Object)# => falsebasic_obj.is_a?(::Integer)# => falsebasic_obj.kind_of?(::Integer)# => falsebasic_obj.frozen?# => falsebasic_obj.freeze# => selfbasic_obj.frozen?# => truebasic_obj.nil?# => falsebasic_obj.hash# => 2682859680348634421 (some Integer value)basic_obj.inspect# => "#<BasicObject:0x00007fe428018628>"- works with an array of proc objects;
- returns the result of the first non-failed proc;
- provides an error interception interface (a block argument);
- fails with the last failed proc exception (if all procs were failed and interceptor was not passed);
SmartCore::Engine::RescueExt.inline_rescue_pipe(->{raise},->{raise},->{123},->{567},->{raise},)# => output: 123SmartCore::Engine::RescueExt.inline_rescue_pipe(->{raise(::ArgumentError)},->{raise(::TypeError)},->{raise(::ZeroDivisionError)})# => fails with ZeroDivisionErrorSmartCore::Engine::RescueExt.inline_rescue_pipe(->{raise(::ArgumentError)},->{raise(::TypeError)},->{raise(::ZeroDivisionError,'Intercepted exception')})do |error|
error.messageend# => output: "Intercepted exception"- migrate to Github Actions in CI;
- thread-safety for BasicObject extensions;
SmartCore::Engine::Cache:- thread-safety;
- support for
ttl:option for#writeand for fallback block attribute of#read; - support for key-value-pair iteration;
- support for
#keysmethod; - support for
#key?method; - think about some layer of cache object serialization;
SmartCore::Engine::ReadWriteLock:- an ability to set a maximum count of readers;
- Fork it ( https://github.com/smart-rb/smart_engine )
- Create your feature branch (
git checkout -b feature/my-new-feature) - Commit your changes (
git commit -am '[feature_context] Add some feature') - Push to the branch (
git push origin feature/my-new-feature) - Create new Pull Request
Released under MIT License.
