dumpling 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 27b87ea50d627fb4bf537b97334435165f0550dc
4
- data.tar.gz: 084c021f548b392e1e0aa749d7a5566e5ff9b4a2
3
+ metadata.gz: 07ff2f1a56d0fabcfefe29dec5322d7ff2f57eb6
4
+ data.tar.gz: bead658711229742bb88e919d913af3257a19883
5
5
  SHA512:
6
- metadata.gz: 6e9fceb60dcfb9464d028d6fb34ab1f7358f14ff21abd93b65f7dbef581353ba2bc445895120fa1ebac5bc57d9276b00fb941f0063801d7610293b10e52e98be
7
- data.tar.gz: e7dcdc818d2a6df4eeea40032bbf2cb85ab0db228b3350d4db1361991fe943de2c0752d17c6a6271f509e9f3fafe8e4e81a16bdf4e90726a5957b799eeac8822
6
+ metadata.gz: cf8af125eed37639db305a1fe6639cdb0c91fb2402d24826423909b05f3d53d7bc2531442244917a5597b53d0652ea77e3485cf3c5281b8247757be9385c3d82
7
+ data.tar.gz: 3b2946aeb843ff9f916b25e495a1d577a6ce5cf91a966464f64a630dc28bb9d56a11ac68bcd9d1302068efe11c96c09020dfecc5a28aaf14bf6bcd344df53b7e
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Dumpling
2
2
 
3
- TODO: Describe your gem
3
+ Dumpling provides you an unobtrusive way to manage dependencies.
4
+ What is unobtrusive? Unobtrusive means that you don't need to include a module or inherit a class anywhere in your project.
5
+ Dumpling does not tie your hands. All you have to do is just wire up dependencies.
4
6
 
5
7
  ## Installation
6
8
 
@@ -18,9 +20,105 @@ Or install it yourself as:
18
20
 
19
21
  $ gem install dumpling
20
22
 
21
- ## Usage
23
+ ## Getting started
22
24
 
23
- TODO: Write usage instructions here
25
+ ### Basics
26
+
27
+ ```ruby
28
+ class UsersRepository
29
+ attr_writer :logger
30
+ end
31
+
32
+ Dumpling.configure do
33
+ set :logger do |s|
34
+ s.instance Logger.new(STDOUT) # => #<Logger:0x00000000e281a0>
35
+ end
36
+
37
+ set :users_repository do |s|
38
+ s.class UsersRepository
39
+ s.dependency :logger
40
+ end
41
+ end
42
+
43
+ # Every time you invoke the #get method you will get a new instance of the #class
44
+ Dumpling.get(:users_repository) # => #<UsersRepository:0x00000000ebee20>
45
+ Dumpling.get(:users_repository) # => #<UsersRepository:0x00000000e8a8f0>
46
+
47
+ # Every time you invoke the #get method you will get the same predefined #instance
48
+ Dumpling.get(:logger) # => #<Logger:0x00000000e281a0>
49
+ Dumpling.get(:logger) # => #<Logger:0x00000000e281a0>
50
+ ```
51
+
52
+ ### Defining multiple dependencies
53
+
54
+ ```ruby
55
+ container = Dumpling::Container.new
56
+ container.configure do
57
+ set :logger do |s|
58
+ s.instance Logger.new(STDOUT) # => #<Logger:0x00000000e281a0>
59
+ end
60
+
61
+ set :adapter do |s|
62
+ s.instance PostgreSQLAdapter.new
63
+ s.dependency :logger
64
+ end
65
+
66
+ set :users_repository do |s|
67
+ s.class UsersRepository
68
+ s.dependency :logger
69
+ s.dependency :adapter
70
+ end
71
+ end
72
+
73
+ class UsersRepository
74
+ attr_accessor :logger, :adapter
75
+
76
+ # You can mark a setter method as a private if you need
77
+ private :adapter=, :logger=
78
+ end
79
+
80
+ container.get(:users_repository).logger # => #<Logger:0x00000000e281a0>
81
+ container[:users_repository].adapter.logger # => #<Logger:0x00000000e281a0>
82
+ # Logger will be injected every time an adapter is accessed
83
+ container[:adapter].logger # => #<Logger:0x00000000e281a0>
84
+ ```
85
+
86
+ ### Using namespaces
87
+
88
+ ```ruby
89
+ container = Dumpling::Container.new
90
+ container.configure do
91
+ # All that does not match [a-zA-Z0-9_] is a delimiter
92
+ set :'billing:repositories:users' do |s|
93
+ ...
94
+ end
95
+
96
+ set :'billing repositories users' do |s|
97
+ ...
98
+ end
99
+
100
+ set :'billing.repositories.users' do |s|
101
+ ...
102
+ end
103
+
104
+ # Delimiters can be mixed up
105
+ set :'billing repositories-users' do |s|
106
+ ...
107
+ end
108
+
109
+ set :'billing.commands.create' do |s|
110
+ s.class Billing::Commands::Create
111
+ # Will automatically guess the name of the attr_writer by the last word (attr_writer :users)
112
+ s.dependency :'billing.repositories.users'
113
+ end
114
+
115
+ set :'billing.commands.open_dispute' do |s|
116
+ s.class Billing::Commands::OpenDispute
117
+ # Define the attr_writer explicitly (attr_writer :customers)
118
+ s.dependency :'billing.repositories.users', attribute: :customers
119
+ end
120
+ end
121
+ ```
24
122
 
25
123
  ## Development
26
124
 
data/dumpling.gemspec CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.homepage = 'https://github.com/antonkuzmenko/dumpling'
12
12
  spec.license = 'MIT'
13
13
 
14
- spec.summary = 'Dumpling is a simple Dependency Injection Container'
14
+ spec.summary = 'Dumpling is an unobtrusive Dependency Injection Container'
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\Aspec/}) }
17
17
  spec.require_paths = ['lib']
@@ -22,4 +22,5 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency 'rake', '~> 10.0'
23
23
  spec.add_development_dependency 'rspec', '~> 3.0'
24
24
  spec.add_development_dependency 'rubocop', '~> 0.36.0'
25
+ spec.add_development_dependency 'simplecov', '~> 0.11'
25
26
  end
data/lib/dumpling.rb CHANGED
@@ -7,5 +7,14 @@ module Dumpling
7
7
  require 'dumpling/errors/specification'
8
8
  require 'dumpling/specification'
9
9
  require 'dumpling/specification_validator'
10
+ require 'dumpling/registry'
10
11
  require 'dumpling/container'
12
+
13
+ @container = Container.new
14
+
15
+ class << self
16
+ extend Forwardable
17
+
18
+ def_delegators :@container, :set, :get, :[], :configure
19
+ end
11
20
  end
@@ -1,14 +1,24 @@
1
1
  module Dumpling
2
2
  class Container
3
+ attr_writer :validator_class
4
+
3
5
  def initialize
4
- @id_list = Set.new
5
- @registry = {}
6
+ @registry = Registry.new
7
+ @validator_class = SpecificationValidator
8
+ end
9
+
10
+ def set(id, &block)
11
+ fail(Errors::Container::Duplicate, id) if @registry.has?(id)
12
+
13
+ specification = create_specification(&block)
14
+ @registry.set(id, specification)
15
+
16
+ id
6
17
  end
7
18
 
8
19
  def get(id)
9
- id = id.to_sym
10
- fail(Errors::Container::Missing, id) unless @id_list.include?(id)
11
- specification = @registry[id]
20
+ fail(Errors::Container::Missing, id) unless @registry.has?(id)
21
+ specification = @registry.get(id)
12
22
  instance = build_instance(specification)
13
23
  inject_dependencies(instance, specification)
14
24
  instance
@@ -16,21 +26,6 @@ module Dumpling
16
26
 
17
27
  alias :[] get
18
28
 
19
- def set(id)
20
- id = id.to_sym
21
- fail(Errors::Container::Duplicate, id) if @id_list.include?(id)
22
-
23
- specification = Specification.new
24
- yield specification
25
- SpecificationValidator.new(@id_list, specification).validate!
26
- @registry[id] = specification
27
- @id_list << id
28
-
29
- nil
30
- end
31
-
32
- alias :[]= set
33
-
34
29
  def configure(&block)
35
30
  instance_eval(&block)
36
31
  self
@@ -38,13 +33,20 @@ module Dumpling
38
33
 
39
34
  private
40
35
 
36
+ def create_specification
37
+ specification = Specification.new
38
+ yield specification
39
+ @validator_class.new(@registry.keys, specification).validate!
40
+ specification
41
+ end
42
+
41
43
  def build_instance(specification)
42
44
  specification.class.nil? ? specification.instance : specification.class.new
43
45
  end
44
46
 
45
47
  def inject_dependencies(instance, specification)
46
48
  specification.dependencies.each do |dependency|
47
- instance.send("#{dependency[:attr]}=", get(dependency[:id]))
49
+ instance.send("#{dependency[:attribute]}=", get(dependency[:id]))
48
50
  end
49
51
  end
50
52
  end
@@ -6,9 +6,6 @@ module Dumpling
6
6
 
7
7
  class MissingDependencies < Invalid
8
8
  end
9
-
10
- class NotClass < Invalid
11
- end
12
9
  end
13
10
  end
14
11
  end
@@ -0,0 +1,25 @@
1
+ module Dumpling
2
+ class Registry
3
+ attr_reader :keys
4
+
5
+ def initialize
6
+ @data = {}
7
+ @keys = Set.new
8
+ end
9
+
10
+ def set(id, value)
11
+ @data[id] = value
12
+ @keys << id
13
+
14
+ value
15
+ end
16
+
17
+ def get(id)
18
+ @data[id]
19
+ end
20
+
21
+ def has?(id)
22
+ @keys.include?(id)
23
+ end
24
+ end
25
+ end
@@ -14,15 +14,15 @@ module Dumpling
14
14
  instance.nil? ? @instance : (@instance = instance)
15
15
  end
16
16
 
17
- def inject(id, attr: nil)
18
- dependencies << { id: id.to_sym, attr: (attr || guess_attribute(id)).to_sym }
17
+ def dependency(id, attribute: nil)
18
+ dependencies << { id: id, attribute: (attribute || guess_attribute(id)).to_sym }
19
19
  end
20
20
 
21
21
  private
22
22
 
23
23
  def guess_attribute(id)
24
- /(?<attr>\w+)\z/i =~ id
25
- attr || id
24
+ /(?<attribute>\w+)\z/i =~ id
25
+ attribute || id
26
26
  end
27
27
  end
28
28
  end
@@ -13,8 +13,13 @@ module Dumpling
13
13
  private
14
14
 
15
15
  def validate_value
16
+ unless @specification.class.nil? || @specification.instance.nil?
17
+ fail Errors::Specification::Invalid,
18
+ 'Do not define both #class and #instance at the same time'
19
+ end
20
+
16
21
  if @specification.class.nil? && @specification.instance.nil?
17
- fail Errors::Specification::Invalid, 'You must define #class or #instance'
22
+ fail Errors::Specification::Invalid, 'Define #class or #instance'
18
23
  end
19
24
  end
20
25
 
@@ -29,8 +34,8 @@ module Dumpling
29
34
  def missing_dependencies
30
35
  @specification
31
36
  .dependencies
32
- .reject { |e| @id_list.include?(e[:id]) }
33
37
  .map { |e| e[:id] }
38
+ .reject { |e| @id_list.include?(e) }
34
39
  end
35
40
  end
36
41
  end
@@ -1,7 +1,7 @@
1
1
  module Dumpling
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 1
4
+ MINOR = 2
5
5
  TINY = 0
6
6
  PRE = nil
7
7
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dumpling
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Kuzmenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-28 00:00:00.000000000 Z
11
+ date: 2016-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.36.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.11'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.11'
69
83
  description:
70
84
  email: antonkuzmenko.dev@gmail.com
71
85
  executables: []
@@ -89,6 +103,7 @@ files:
89
103
  - lib/dumpling/errors/base_error.rb
90
104
  - lib/dumpling/errors/container.rb
91
105
  - lib/dumpling/errors/specification.rb
106
+ - lib/dumpling/registry.rb
92
107
  - lib/dumpling/specification.rb
93
108
  - lib/dumpling/specification_validator.rb
94
109
  - lib/dumpling/version.rb
@@ -115,5 +130,5 @@ rubyforge_project:
115
130
  rubygems_version: 2.5.1
116
131
  signing_key:
117
132
  specification_version: 4
118
- summary: Dumpling is a simple Dependency Injection Container
133
+ summary: Dumpling is an unobtrusive Dependency Injection Container
119
134
  test_files: []