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