mini_object 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 42c7b681ee29460d5b652d07069aa46b50dbd3f7
4
+ data.tar.gz: 6b9083abe99eed8a6c42b777984e7f0cab6491ae
5
+ SHA512:
6
+ metadata.gz: fae92c73f7def24ddb55120650925f6ecfedb8e322ce1be48d6aa970be5979e8a76ebbb29625ea8d5efae1f03b468e7a57204378d4f2b4b2fcb90445d777c59d
7
+ data.tar.gz: 696a5b683d06e54a23ebecb377245c71fd2620c8b785b5502671dc6134eec557253fb5c2241fef0c6711e30803952bd72a1e8a551f31f93f17ee868a39e8381c
data/.gitignore ADDED
File without changes
data/.yardoc/checksums ADDED
@@ -0,0 +1,7 @@
1
+ lib/lazy.rb 7e4d5fabe9a99f5a2751823cd1ea4e67f446ee2e
2
+ lib/inline.rb df7b92b051d5e5072ad5b486576a801fb3a336a7
3
+ lib/section.rb b05f398196140a836f5e125c20f9988f7a7ef000
4
+ lib/version.rb 2b03a00fee65075ba6f4715792ec212a3b47d654
5
+ lib/resolver.rb c4cf365fd98c2d454e2d11404be070b3d46690f6
6
+ lib/injectable.rb c95a2ea2a7500684d293be0c89196887c72ee68a
7
+ lib/mini_object.rb c4541e47c74f1d904221f2067ad9c0fc0e551ea9
Binary file
Binary file
Binary file
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test, :development do
6
+ gem 'rspec', require: false
7
+ gem 'pry', require: false
8
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mini_object (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ coderay (1.1.0)
10
+ diff-lcs (1.2.5)
11
+ method_source (0.8.2)
12
+ pry (0.10.1)
13
+ coderay (~> 1.1.0)
14
+ method_source (~> 0.8.1)
15
+ slop (~> 3.4)
16
+ rake (10.4.2)
17
+ rspec (3.1.0)
18
+ rspec-core (~> 3.1.0)
19
+ rspec-expectations (~> 3.1.0)
20
+ rspec-mocks (~> 3.1.0)
21
+ rspec-core (3.1.7)
22
+ rspec-support (~> 3.1.0)
23
+ rspec-expectations (3.1.2)
24
+ diff-lcs (>= 1.2.0, < 2.0)
25
+ rspec-support (~> 3.1.0)
26
+ rspec-mocks (3.1.3)
27
+ rspec-support (~> 3.1.0)
28
+ rspec-support (3.1.2)
29
+ slop (3.6.0)
30
+
31
+ PLATFORMS
32
+ ruby
33
+
34
+ DEPENDENCIES
35
+ bundler (~> 1.3)
36
+ mini_object!
37
+ pry
38
+ rake
39
+ rspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2014 Manuel Morales, Workshare ltd., et al.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # MiniObject
2
+
3
+ A set of tools which will make easier to work with objects instead of classes
4
+ and injecting dependencies.
5
+
6
+
7
+ ## Inline
8
+
9
+ Allows defining objects ad-hoc passing an initialization block.
10
+
11
+ ```ruby
12
+ homer = Inline.new 'Homer Simpson' do
13
+ def talk
14
+ 'Doh!'
15
+ end
16
+
17
+ def sleep
18
+ end
19
+ end
20
+ # => < Homer Simpson / Inline : talk, sleep >
21
+
22
+ homer.talk
23
+ # => 'Doh!'
24
+ ```
25
+
26
+ ## Injectable
27
+
28
+ Makes easier and nicer to assign values and inject dependencies to objects.
29
+ The key feature is the ability to assign lambdas as way to resolve the value:
30
+
31
+ ```ruby
32
+ class UsersRepository
33
+ include Injectable
34
+ attr_injectable :store
35
+ end
36
+
37
+ users_repo = UsersRepository.new
38
+ users_repo.store{ app.stores.redis }
39
+ ```
40
+
41
+ In the example, if `app.stores.persistent` changes, the repository
42
+ will inmediately see the new store.
43
+
44
+
45
+ ## RemarkableInspect
46
+
47
+ Provides an `inspect` and `to_s` which focus on methods:
48
+
49
+ ```ruby
50
+ class Application
51
+ include RemarkableInspect
52
+
53
+ def config; end
54
+ def config=; end
55
+ def stores; end
56
+ end
57
+ # => Application( config/=, stores )
58
+
59
+ Application.new
60
+ # => < Application : config/=, stores >
61
+ ```
62
+
63
+ ## Lazy
64
+
65
+ A proxy that will lazy evaluate the proxied object.
66
+ Useful when an object expect an dependency but we want to
67
+ instantiate it only on demand:
68
+
69
+ ```ruby
70
+ users_repository.store = Lazy.new { Redis.new }
71
+ ```
72
+
73
+ This way `Redis.new` will only be executed when `users_repository.store`
74
+ it is called for the first time.
75
+
76
+ It also allows defining build callbacks:
77
+
78
+ ```ruby
79
+ users_repository.store = Lazy.new { Redis.new }
80
+ users_repository.build_step(:clear) { |redis| redis.flushdb }
81
+ ```
82
+
83
+
84
+ ## Resolver
85
+
86
+ A proxy that will always evaluate the given block.
87
+ Useful when an object expect an dependency but we want it
88
+ to be resolved on demand:
89
+
90
+ ```ruby
91
+ users_repository.store = Lazy.new{ app.stores.redis }
92
+ ```
93
+
94
+ In the example, if `app.stores.redis`, the repository
95
+ will inmediately see the new store.
96
+
97
+
98
+ ## Contributing
99
+
100
+ Do not forget to run the tests with:
101
+
102
+ ```bash
103
+ rake
104
+ ```
105
+
106
+ And bump the version with any of:
107
+
108
+ ```bash
109
+ $ gem bump --version 1.1.1 # Bump the gem version to the given version number
110
+ $ gem bump --version major # Bump the gem version to the next major level (e.g. 0.0.1 to 1.0.0)
111
+ $ gem bump --version minor # Bump the gem version to the next minor level (e.g. 0.0.1 to 0.1.0)
112
+ $ gem bump --version patch # Bump the gem version to the next patch level (e.g. 0.0.1 to 0.0.2)
113
+ ```
114
+
115
+
116
+ ## License
117
+
118
+ Released under the MIT License.
119
+ See the [LICENSE](LICENSE.txt) file for further details.
120
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake'
3
+
4
+ require 'rspec/core/rake_task'
5
+ task :default => :spec
6
+ task :test => :spec
7
+ desc 'Run all specs'
8
+ RSpec::Core::RakeTask.new('spec') do |spec|
9
+ spec.rspec_opts = %w{}
10
+ end
data/lib/box.rb ADDED
@@ -0,0 +1,10 @@
1
+ module MiniObject
2
+ class Box
3
+ include Injectable
4
+ include RemarkableInspect
5
+
6
+ def initialize attrs = {}
7
+ self.attributes= attrs
8
+ end
9
+ end
10
+ end
data/lib/injectable.rb ADDED
@@ -0,0 +1,73 @@
1
+ module MiniObject
2
+ module Injectable
3
+ NULL = Object.new
4
+
5
+ def initialize &block
6
+ super
7
+ block.call self if block
8
+ end
9
+
10
+ def self.included klass
11
+ klass.extend self
12
+ end
13
+
14
+ def self.getsetter_definition_for name
15
+ lambda do |value = NULL, &block|
16
+ if block
17
+ if value == NULL || value == nil
18
+ instance_variable_set("@#{name}_proc", block)
19
+ else
20
+ send("#{name}=", value)
21
+ end
22
+ else
23
+ if value == NULL
24
+ p = instance_variable_get("@#{name}_proc")
25
+ p || raise("No #{name} defined yet for #{inspect}")
26
+ p.call
27
+ else
28
+ send("#{name}=", value)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def self.setter_definition_for name
35
+ lambda do |value|
36
+ instance_variable_set("@#{name}_proc", lambda{ value })
37
+ value
38
+ end
39
+ end
40
+
41
+ def cattr_injectable name
42
+ define_singleton_method name, &Injectable.getsetter_definition_for(name)
43
+ define_singleton_method "#{name}=", &Injectable.setter_definition_for(name)
44
+ end
45
+
46
+ def attr_injectable name
47
+ define_method name, &Injectable.getsetter_definition_for(name)
48
+ define_method "#{name}=", &Injectable.setter_definition_for(name)
49
+ end
50
+
51
+ def let name, &block
52
+ var_name = :"@#{name}"
53
+
54
+ define_singleton_method "#{name}=" do |value|
55
+ instance_variable_set var_name, value
56
+ end
57
+
58
+ define_singleton_method name do
59
+ if instance_variable_defined? var_name
60
+ instance_variable_get var_name
61
+ else
62
+ instance_variable_set var_name, block.call(self)
63
+ end
64
+ end
65
+ end
66
+
67
+ def attributes= attrs
68
+ attrs.each do |k,v|
69
+ public_send "#{k}=", v
70
+ end
71
+ end
72
+ end
73
+ end
data/lib/inline.rb ADDED
@@ -0,0 +1,24 @@
1
+ module MiniObject
2
+ class Inline
3
+ include Injectable
4
+ include RemarkableInspect
5
+
6
+ attr_accessor :inline_name
7
+
8
+ def initialize name = nil, &block
9
+ @inline_name = name || 'inline'
10
+ instance_exec self, &block if block
11
+ end
12
+
13
+ def remarkable_methods
14
+ methods - self.class.instance_methods
15
+ end
16
+
17
+ def remarkable_name
18
+ "#{inline_name || 'anon'} / Inline"
19
+ end
20
+
21
+ # TODO: Explore the possiblity of allowing access to methods and
22
+ # vars defined outside the block.
23
+ end
24
+ end
data/lib/lazy.rb ADDED
@@ -0,0 +1,63 @@
1
+ require 'delegate'
2
+
3
+ module MiniObject
4
+ class Lazy < Delegator
5
+ attr_accessor :lazy_name
6
+
7
+ def initialize name = nil, &block
8
+ self.lazy_name = name
9
+ @block = block
10
+ end
11
+
12
+ def __getobj__
13
+ @obj ||= @block.call.tap do |obj|
14
+ build_steps.each do |name, block|
15
+ block.call obj
16
+ end
17
+ end
18
+ end
19
+
20
+ alias get_obj __getobj__
21
+
22
+ def resolver_bound
23
+ @block.binding.eval('self')
24
+ end
25
+
26
+ def build_step name, &block
27
+ build_steps[name] = block
28
+ end
29
+
30
+ def build &block
31
+ @block = block
32
+ end
33
+
34
+ def inspect
35
+ prefix = lazy_name ? "#{lazy_name}: " : ""
36
+ steps = " " + build_steps.keys.join(", ") if build_steps.any?
37
+ "< #{prefix}Lazy(#{formatted_block_source}#{steps}) >"
38
+ end
39
+
40
+ alias to_s inspect
41
+
42
+ private
43
+
44
+ def build_steps
45
+ @build_steps ||= {}
46
+ end
47
+
48
+ def block_source
49
+ require 'method_source'
50
+ begin
51
+ MethodSource.source_helper(@block.source_location)
52
+ rescue MethodSource::SourceNotFoundError
53
+ '{???}'
54
+ end
55
+ end
56
+
57
+ def formatted_block_source
58
+ code = block_source.split("\n").map(&:strip).join("; ")
59
+ code = code[0..59] + "\u2026" if code.length > 60
60
+ code.inspect
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,12 @@
1
+ require "version"
2
+
3
+ module MiniObject
4
+ autoload :Lazy, 'lazy'
5
+ autoload :Injectable, 'injectable'
6
+ autoload :Resolver, 'resolver'
7
+ autoload :Inline, 'inline'
8
+ autoload :Toolbox, 'toolbox'
9
+ autoload :Tool, 'tool'
10
+ autoload :ForwardingDSL, 'forwarding_dsl'
11
+ autoload :RemarkableInspect, 'remarkable_inspect'
12
+ end
@@ -0,0 +1,47 @@
1
+ module MiniObject
2
+ module RemarkableInspect
3
+ def to_s
4
+ "< #{remarkable_name} : #{remarkable_methods.join(", ")} >"
5
+ end
6
+
7
+ alias inspect to_s
8
+
9
+ def self.included klass
10
+ klass.extend ClassMethods
11
+ end
12
+
13
+ private
14
+
15
+ def remarkable_methods
16
+ self.class.remarkable_methods
17
+ end
18
+
19
+ def remarkable_name
20
+ self.class.name
21
+ end
22
+
23
+ module ClassMethods
24
+ def inspect
25
+ "#{formatted_name}( #{remarkable_methods.join(", ")} )"
26
+ end
27
+
28
+ def remarkable_methods
29
+ (self.instance_methods - Box.instance_methods).map(&:to_s).tap do |mm|
30
+ # Substittues [my_method, my_method=] by [my_method/=]
31
+ mm.grep(/\=$/).each do |setter|
32
+ getter = setter.gsub /\=$/, ''
33
+ if mm.include? getter
34
+ mm.delete setter
35
+ mm[mm.find_index(getter)] = setter.gsub /\=$/, '/='
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ def formatted_name
42
+ first_ancestor_name = ancestors.map(&:name).compact.first
43
+ name || "#{first_ancestor_name}:0x#{'%x' % (object_id << 1)}"
44
+ end
45
+ end
46
+ end
47
+ end
data/lib/resolver.rb ADDED
@@ -0,0 +1,15 @@
1
+ module MiniObject
2
+ class Resolver < Delegator
3
+ def initialize &block
4
+ @block = block
5
+ end
6
+
7
+ def __getobj__
8
+ @block.call
9
+ end
10
+
11
+ def resolver_bound
12
+ @block.binding.eval('self')
13
+ end
14
+ end
15
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module MiniObject
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ gem_name = "mini_object"
3
+
4
+ lib = File.expand_path('../lib', __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+ require "#{gem_name}"
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = gem_name
10
+ spec.version = MiniObject::VERSION
11
+ spec.authors = ["Manuel Morales"]
12
+ spec.email = ['manuelmorales@gmail.com']
13
+ spec.description = File.read('README.md').split("\n").reject{|l| l.length == 0 || l =~ /^[#=]+/ }.first
14
+ spec.summary = spec.description
15
+ spec.homepage = "https://github.com/manuelmorales/#{spec.name.gsub('_','-')}"
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files`.split($/)
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ end
data/spec/box_spec.rb ADDED
@@ -0,0 +1,126 @@
1
+ require_relative 'spec_helper'
2
+ require 'box'
3
+
4
+ describe 'Box' do
5
+ it 'allows nested boxes' do
6
+
7
+ stub_const 'Stores', Class.new(Box) {
8
+ def memory
9
+ :memory_store
10
+ end
11
+ }
12
+
13
+ stub_const 'BoxApp', Class.new(Box) {
14
+ def stores
15
+ @stores ||= Stores.new
16
+ end
17
+ }
18
+
19
+ expect(BoxApp.new.stores.memory).to eq :memory_store
20
+ end
21
+
22
+ it 'allows tools requiring a config' do
23
+
24
+ stub_const 'Stores', Class.new(Box) {
25
+ attr_accessor :config
26
+
27
+ def hash; {}; end
28
+ def array; []; end
29
+
30
+ def default
31
+ case config[:default]
32
+ when 'array' then array
33
+ when 'hash' then hash
34
+ end
35
+ end
36
+ }
37
+
38
+ stub_const 'Config', Class.new(Box) {
39
+ def stores
40
+ @stores ||= { default: 'hash' }
41
+ end
42
+ }
43
+
44
+ stub_const 'BoxApp', Class.new(Box) {
45
+ def stores
46
+ @stores ||= Stores.new config: config.stores
47
+ end
48
+
49
+ def config
50
+ @config ||= Config.new
51
+ end
52
+ }
53
+
54
+ subject = BoxApp.new
55
+ expect(subject.stores.default).to eq({})
56
+
57
+ subject.config.stores[:default] = 'array'
58
+ expect(subject.stores.default).to eq([])
59
+ end
60
+
61
+ it 'allows overriding a tool' do
62
+
63
+ stub_const 'BoxApp', Class.new(Box) {
64
+ attr_accessor :store
65
+
66
+ def store
67
+ @store ||= :memory
68
+ end
69
+ }
70
+
71
+ subject = BoxApp.new
72
+ expect(subject.store).to be :memory
73
+
74
+ subject.store = :persistent
75
+ expect(subject.store).to be :persistent
76
+ end
77
+
78
+ it 'allows overriding config files with inheritance' do
79
+ stub_const 'Defaults', { persistent: true, adapter: 'mysql' }
80
+ stub_const 'Overrides', { adapter: 'postgres' }
81
+
82
+ stub_const 'Conf', Class.new(Box) {
83
+ def db
84
+ @db ||= Defaults.merge db_overrides
85
+ end
86
+
87
+ def db_overrides
88
+ {}
89
+ end
90
+ }
91
+
92
+ stub_const 'BoxApp', Class.new(Box) {
93
+ def config
94
+ @config ||= Conf.new
95
+ end
96
+ }
97
+
98
+ stub_const 'TestConf', Class.new(Conf) {
99
+ def db_overrides
100
+ Overrides
101
+ end
102
+ }
103
+
104
+ stub_const 'TestBoxApp', Class.new(BoxApp) {
105
+ def config
106
+ @config ||= TestConf.new
107
+ end
108
+ }
109
+
110
+ expect(BoxApp.new.config.db).to eq({ persistent: true, adapter: 'mysql' })
111
+ expect(TestBoxApp.new.config.db).to eq({ persistent: true, adapter: 'postgres' })
112
+ end
113
+
114
+ it 'looks pretty' do
115
+ stub_const 'BoxApp', Class.new(Box){
116
+ def config; end
117
+ def config=; end
118
+ def stores; end
119
+ }
120
+
121
+ subject = BoxApp.new
122
+
123
+ expect(subject.to_s).to eq('< BoxApp : config/=, stores >')
124
+ expect(BoxApp.inspect).to eq('BoxApp( config/=, stores )')
125
+ end
126
+ end
@@ -0,0 +1,81 @@
1
+ require_relative 'spec_helper'
2
+ require 'injectable'
3
+
4
+ RSpec.describe 'Injectable' do
5
+ shared_examples_for 'having an injectable name' do
6
+ it 'provides getter and setter' do
7
+ expect(subject.name = 'A name').to eq 'A name'
8
+ expect(subject.name).to eq 'A name'
9
+ end
10
+
11
+ it 'allows setting a value without the = sign' do
12
+ expect(subject.name 'A name').to eq 'A name'
13
+ expect(subject.name).to eq 'A name'
14
+ end
15
+
16
+ it 'allows setting nil' do
17
+ subject.name = 'A name'
18
+ expect(subject.name nil).to eq nil
19
+ expect(subject.name).to eq nil
20
+ end
21
+
22
+ it 'allows setting a value with a lambda' do
23
+ subject.name { 'A name' }
24
+ expect(subject.name).to eq 'A name'
25
+ end
26
+
27
+ it 'does not memoize the lambda' do
28
+ counter = 0
29
+ subject.name { counter += 1 }
30
+ expect(subject.name).to eq 1
31
+ expect(subject.name).to eq 2
32
+ end
33
+
34
+ it 'gives priority to the value if both, block and value == nil are given' do
35
+ subject.name('value'){ 'block' }
36
+ expect(subject.name).to eq('value')
37
+
38
+ subject.name(nil) { 'block' }
39
+ expect(subject.name).to eq('block')
40
+ end
41
+ end
42
+
43
+ context 'attr_accessor within a class' do
44
+ let(:subject_class) do
45
+ Class.new do
46
+ include Injectable
47
+ attr_injectable :name
48
+ end
49
+ end
50
+
51
+ subject { subject_class.new }
52
+ it_behaves_like 'having an injectable name'
53
+ end
54
+
55
+ context 'cattr_accessor within a class' do
56
+ let(:subject_class) do
57
+ Class.new do
58
+ include Injectable
59
+ cattr_injectable :name
60
+ end
61
+ end
62
+
63
+ subject { subject_class }
64
+ it_behaves_like 'having an injectable name'
65
+ end
66
+
67
+ describe '#attributes=' do
68
+ let(:subject_class) do
69
+ Class.new do
70
+ include Injectable
71
+ cattr_injectable :name
72
+ end
73
+ end
74
+
75
+ it 'assings each attr' do
76
+ subject = subject_class
77
+ subject.attributes=({ name: 'MyName' })
78
+ expect(subject.name).to eq 'MyName'
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,28 @@
1
+ require_relative 'spec_helper'
2
+
3
+ RSpec.describe 'Inline' do
4
+ it 'allows defining methods with an initialization block' do
5
+ subject = Inline.new do
6
+ def bark
7
+ 'woof'
8
+ end
9
+ end
10
+
11
+ expect(subject.bark).to eq('woof')
12
+ end
13
+
14
+ it 'has an inspect and to_s' do
15
+ subject = Inline.new 'some name' do
16
+ def bark
17
+ 'woof'
18
+ end
19
+
20
+ def sleep
21
+ 'zzz'
22
+ end
23
+ end
24
+
25
+ expect(subject.inspect).to eq("< some name / Inline : bark, sleep >")
26
+ expect(subject.to_s).to eq("< some name / Inline : bark, sleep >")
27
+ end
28
+ end
data/spec/lazy_spec.rb ADDED
@@ -0,0 +1,71 @@
1
+ require_relative 'spec_helper'
2
+
3
+ RSpec.describe 'Lazy' do
4
+ let(:klass) { double('class', new: instance) }
5
+ let(:instance) { double('instance', a_method: 'a_result') }
6
+
7
+ it 'forwards messages to the result of the lambda' do
8
+ subject = Lazy.new{ klass.new }
9
+ expect(subject.a_method).to eq('a_result')
10
+ end
11
+
12
+ it 'is lazy' do
13
+ expect(klass).not_to receive(:new)
14
+ subject = Lazy.new{ klass.new }
15
+ end
16
+
17
+ it 'memoizes the result' do
18
+ expect(klass).to receive(:new).once
19
+ subject = Lazy.new{ klass.new }
20
+
21
+ subject.a_method
22
+ subject.a_method
23
+ end
24
+
25
+ describe 'inspect' do
26
+ it 'has the source code' do
27
+ subject = Lazy.new { klass.new }
28
+ expect(subject.inspect).to match('klass.new')
29
+ end
30
+
31
+ it 'has a name' do
32
+ subject = Lazy.new('The Subject') { klass.new }
33
+ expect(subject.inspect).to match('The Subject')
34
+ end
35
+
36
+ it 'doesn\'t have the name when blank' do
37
+ subject = Lazy.new { klass.new }
38
+ expect(subject.inspect).to match('< Lazy')
39
+ end
40
+
41
+ it 'is aliased as to_s' do
42
+ subject = Lazy.new { klass.new }
43
+ expect(subject.to_s).to match('klass.new')
44
+ end
45
+ end
46
+
47
+ describe 'build_steps' do
48
+ it 'invokes them at build time' do
49
+ subject = Lazy.new { [] }
50
+ subject.build_step(:add_one) { |array| array << 1 }
51
+
52
+ expect(subject.get_obj).to eq([1])
53
+ end
54
+
55
+ it 'allows substituting them' do
56
+ subject = Lazy.new { [] }
57
+ subject.build_step(:add_one) { |array| array << 1 }
58
+ subject.build_step(:add_one) { |array| array << :one }
59
+
60
+ expect(subject.get_obj).to eq([:one])
61
+ end
62
+ end
63
+
64
+ describe 'build' do
65
+ it 'assigns the build block' do
66
+ subject = Lazy.new
67
+ subject.build { :one }
68
+ expect(subject.get_obj).to eq :one
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,7 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe MiniObject do
4
+ it 'has a version' do
5
+ expect(MiniObject::VERSION).not_to be_nil
6
+ end
7
+ end
@@ -0,0 +1,43 @@
1
+ require_relative 'spec_helper'
2
+
3
+ RSpec.describe 'RemarkableInspect' do
4
+ subject { SubjectClass.new }
5
+
6
+ before do
7
+ stub_const 'SubjectClass', Class.new {
8
+ include RemarkableInspect
9
+
10
+ def config; end
11
+ def config=; end
12
+ def stores; end
13
+ }
14
+ end
15
+
16
+ describe '#to_s' do
17
+ it 'contains class name and class specific methods' do
18
+ expect(subject.to_s).to eq('< SubjectClass : config/=, stores >')
19
+ end
20
+ end
21
+
22
+ describe '#inspect' do
23
+ it 'contains class name and class specific methods' do
24
+ expect(subject.inspect).to eq('< SubjectClass : config/=, stores >')
25
+ end
26
+ end
27
+
28
+ describe '.to_s' do
29
+ it 'contains just the class name' do
30
+ expect(SubjectClass.to_s).to eq('SubjectClass')
31
+ end
32
+ end
33
+
34
+ describe '.inspect' do
35
+ it 'contains class name and class specific methods' do
36
+ expect(SubjectClass.inspect).to eq('SubjectClass( config/=, stores )')
37
+ end
38
+
39
+ it 'contains the object hash in anonymous classes' do
40
+ expect(Class.new(SubjectClass).inspect).to match(/SubjectClass:0x.*\( config\/=, stores \)/)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,26 @@
1
+ require_relative 'spec_helper'
2
+
3
+ RSpec.describe 'Resolver' do
4
+ it 'delegates to the result of evaluating the lambda' do
5
+ target = double('target')
6
+ subject = Resolver.new { target }
7
+
8
+ expect(target).to receive(:a_method)
9
+ subject.a_method
10
+ end
11
+
12
+ it 'will always point to the latest value' do
13
+ target = old_target = double('OLD target')
14
+ subject = Resolver.new { target }
15
+
16
+ target = new_target = double('NEW target')
17
+ expect(new_target).to receive(:a_method)
18
+
19
+ subject.a_method
20
+ end
21
+
22
+ it '#resolver_bound returns the object owner of the binding' do
23
+ subject = Resolver.new { 2 + 2 }
24
+ expect(subject.resolver_bound).to eq self
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'pry'
4
+
5
+ RSpec.configure do |config|
6
+ config.color = true
7
+ config.tty = true
8
+ end
9
+
10
+ $LOAD_PATH.unshift File.expand_path('lib')
11
+ require 'mini_object'
12
+ include MiniObject
13
+
14
+ $LOAD_PATH.unshift File.expand_path('spec/support')
15
+
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mini_object
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Manuel Morales
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A set of tools which will make easier to work with objects instead of
42
+ classes
43
+ email:
44
+ - manuelmorales@gmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - ".yardoc/checksums"
51
+ - ".yardoc/object_types"
52
+ - ".yardoc/objects/root.dat"
53
+ - ".yardoc/proxy_types"
54
+ - Gemfile
55
+ - Gemfile.lock
56
+ - LICENSE.txt
57
+ - README.md
58
+ - Rakefile
59
+ - lib/box.rb
60
+ - lib/injectable.rb
61
+ - lib/inline.rb
62
+ - lib/lazy.rb
63
+ - lib/mini_object.rb
64
+ - lib/remarkable_inspect.rb
65
+ - lib/resolver.rb
66
+ - lib/version.rb
67
+ - mini_object.gemspec
68
+ - spec/box_spec.rb
69
+ - spec/injectable_spec.rb
70
+ - spec/inline_spec.rb
71
+ - spec/lazy_spec.rb
72
+ - spec/mini_object_spec.rb
73
+ - spec/remarkable_inspect_spec.rb
74
+ - spec/resolver_spec.rb
75
+ - spec/spec_helper.rb
76
+ homepage: https://github.com/manuelmorales/mini-object
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.2.2
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: A set of tools which will make easier to work with objects instead of classes
100
+ test_files:
101
+ - spec/box_spec.rb
102
+ - spec/injectable_spec.rb
103
+ - spec/inline_spec.rb
104
+ - spec/lazy_spec.rb
105
+ - spec/mini_object_spec.rb
106
+ - spec/remarkable_inspect_spec.rb
107
+ - spec/resolver_spec.rb
108
+ - spec/spec_helper.rb
109
+ has_rdoc: