mini_object 0.0.1
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 +7 -0
- data/.gitignore +0 -0
- data/.yardoc/checksums +7 -0
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/.yardoc/proxy_types +0 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +39 -0
- data/LICENSE.txt +21 -0
- data/README.md +120 -0
- data/Rakefile +10 -0
- data/lib/box.rb +10 -0
- data/lib/injectable.rb +73 -0
- data/lib/inline.rb +24 -0
- data/lib/lazy.rb +63 -0
- data/lib/mini_object.rb +12 -0
- data/lib/remarkable_inspect.rb +47 -0
- data/lib/resolver.rb +15 -0
- data/lib/version.rb +3 -0
- data/mini_object.gemspec +25 -0
- data/spec/box_spec.rb +126 -0
- data/spec/injectable_spec.rb +81 -0
- data/spec/inline_spec.rb +28 -0
- data/spec/lazy_spec.rb +71 -0
- data/spec/mini_object_spec.rb +7 -0
- data/spec/remarkable_inspect_spec.rb +43 -0
- data/spec/resolver_spec.rb +26 -0
- data/spec/spec_helper.rb +15 -0
- metadata +109 -0
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
|
data/.yardoc/proxy_types
ADDED
Binary file
|
data/Gemfile
ADDED
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
data/lib/box.rb
ADDED
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
|
data/lib/mini_object.rb
ADDED
@@ -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
data/lib/version.rb
ADDED
data/mini_object.gemspec
ADDED
@@ -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
|
data/spec/inline_spec.rb
ADDED
@@ -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,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
|
data/spec/spec_helper.rb
ADDED
@@ -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:
|