README.md in smart_container-0.7.0 vs README.md in smart_container-0.8.0

- old
+ new

@@ -20,14 +20,32 @@ require 'smart_core/container' ``` --- -## Synopsis (demo) +## Table of cotnents -- container class creation: +- [Functionality](#functionality) + - [container class creation](#container-class-creation) + - [mixin](#mixin) + - [container instantiation and dependency resolving](#container-instantiation-and-dependency-resolving) + - [runtime-level dependency/namespace registration](#runtime-level-dependencynamespace-registration) + - [container keys (dependency names)](#container-keys-dependency-names) + - [key predicates](#key-predicates) + - [state freeze](#state-freeze) + - [reloading](#reloading) + - [hash tree](#hash-tree) + - [explicit class definition](#explicit-class-definition) + - [dependency changement observing](#dependency-changement-observing) +- [Roadmap](#roadmap) +--- + +## Functionality + +#### container class creation + ```ruby class Container < SmartCore::Container namespace(:database) do # support for namespaces register(:resolver, memoize: true) { SomeDatabaseResolver.new } # dependency registration @@ -43,12 +61,14 @@ # dependencies are not memoized by default (memoize: false) register(:random) { rand(1000) } end ``` -- mixin: +--- +#### mixin + ```ruby # full documentaiton is coming; class Application include SmartCore::Container::Mixin @@ -63,12 +83,14 @@ # access: Application.container Application.new.container # NOTE: the same instance as Application.container ``` -- container instantiation and dependency resolving: +--- +#### container instantiation and dependency resolving + ```ruby container = Container.new # create container instance ``` ```ruby @@ -88,12 +110,14 @@ # but you can fetch any depenendency type (internal containers and values) via #fetch container.fetch('database') # => SmartCore::Container (nested container) container.fetch('database.resolver') # => #<SomeDatabaseResolver:0x00007f0f0f1d6332> ``` -- runtime-level dependency/namespace registration: +--- +#### runtime-level dependency/namespace registration + ```ruby container.namespace(:api) do register(:provider) { GoogleProvider } # without memoization end @@ -101,12 +125,14 @@ container['api.provider'] # => GoogleProvider container['game_api'] # => 'overwatch' ``` -- container keys (dependency names): +--- +#### container keys (dependency names): + ```ruby # get dependnecy keys (only dependencies) container.keys # => result: [ @@ -130,17 +156,20 @@ 'logger', 'random' ] ``` -- key predicates: - - `key?(key)` - has dependency or namespace? - - `namespace?(path)` - has namespace? - - `dependency?(path)` - has dependency? - - `dependency?(path, memoized: true)` - has memoized dependency? - - `dependency?(path, memoized: false)` - has non-memoized dependency? +--- +#### key predicates + +- `key?(key)` - has dependency or namespace? +- `namespace?(path)` - has namespace? +- `dependency?(path)` - has dependency? +- `dependency?(path, memoized: true)` - has memoized dependency? +- `dependency?(path, memoized: false)` - has non-memoized dependency? + ```ruby container.key?('database') # => true container.key?('database.cache.memcached') # => true container.dependency?('database') # => false @@ -154,28 +183,44 @@ container.dependency?('random', memoized: true) # => false container.dependency?('random', memoized: false) # => true ``` +--- + +#### state freeze + - state freeze (`#freeze!`, `.#frozen?`): ```ruby # documentation is coming; ``` -- reloading (`#reload!): +--- +#### reloading + +- reloading (`#reload!`): + ```ruby # documentation is coming; ``` +--- + +#### hash tree + - hash tree (`#hash_tree`, `#hash_tree(resolve_dependencies: true)`): ```ruby -# documentation is coming`; +# documentation is coming; ``` +--- + +#### explicit class definition + - `SmartCore::Container.define` - avoid explicit class definition (allows to create container instance from an anonymous container class immidietly): ```ruby # - create from empty container class - @@ -210,12 +255,65 @@ AppContainer['db_driver'] # => Sequel (AppContainer dependency) ``` --- +#### dependency changement observing + +- features and limitations: + - you can subscribe only on container instances (on container instance changements); + - at this moment only the full entity path patterns are supported (pattern-based pathes are not supported yet); + - you can subscribe on namespace changements (when the full namespace is re-registered) and dependency changement (when some dependency has been changed); + - `#observe(path, &observer) => observer` - subscribe a custom block to dependency changement events (your proc will be invoked with `|path, container|` attributes); + - `#unobserve(observer)` - unsubscribe concrete observer from dependency observing (returns `true` (unsubscribed) or `false` (nothing to unsubscribe)); + - `#clear_observers(entity_path = nil)` - unsubscribe all observers from concrete path or from all pathes (`nil` parameters); +- aliases: + - `#observe` => `#subscribe`; + - `#unobserve` => `#unsubscribe`; + - `#clear_observers` => `#clear_listeners`; + +```ruby +container = SmartCore::Container.define do + namespace(:database) do + register(:stats) { 'stat_db' } + end +end +``` + +```ruby +# observe entity change +entity_observer = container.observe('database.stats') do |dependency_path, container| + puts "changed => '#{container[dependency_path]}'" +end + +# observe namespace change +namespace_observer = container.observe('database') do |namespace_path, container| + puts "changed => '#{namespace_path}'" +end +``` + +```ruby +container.register('database.stats') { 'kek' } # => invokes entity_observer and outputs "changed! => 'kek'" +container.namespace('database') {} # => invoks namespace_observer and outputs "changed => 'database'" + +container.unobserve(observer) # unsubscribe entity_observer from dependency changement observing; +container.clear_observers # unsubscribe all observers + +container.register('database.stats') { 'kek' } # no one to listen this changement... :) +container.namespace('database') {} # no one to listen this changement... :) +``` + +--- + ## Roadmap +- pattern-based pathes in dependency changement observing; + +```ruby +container.observe('path.*') { puts 'kek!' } # subscribe to all changements in `path` namespace; +``` + - support for instant dependency registration: ```ruby # common (dynamic) way: register('dependency_name') { dependency_value } @@ -229,9 +327,11 @@ ```ruby resolve('logger', :allocate) # Draft ``` - container composition; + +- support for fallback block in `.resolve` operation (similar to `Hash#fetch` works); --- ## Contributing