halogen 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 +15 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +244 -0
- data/Rakefile +6 -0
- data/examples/extensions.md +25 -0
- data/examples/simple.rb +142 -0
- data/halogen.gemspec +32 -0
- data/lib/halogen.rb +157 -0
- data/lib/halogen/collection.rb +44 -0
- data/lib/halogen/configuration.rb +15 -0
- data/lib/halogen/definition.rb +73 -0
- data/lib/halogen/definitions.rb +23 -0
- data/lib/halogen/embeds.rb +105 -0
- data/lib/halogen/embeds/definition.rb +19 -0
- data/lib/halogen/errors.rb +7 -0
- data/lib/halogen/hash_util.rb +37 -0
- data/lib/halogen/links.rb +41 -0
- data/lib/halogen/links/definition.rb +59 -0
- data/lib/halogen/properties.rb +40 -0
- data/lib/halogen/properties/definition.rb +8 -0
- data/lib/halogen/railtie.rb +11 -0
- data/lib/halogen/resource.rb +58 -0
- data/lib/halogen/version.rb +5 -0
- data/spec/halogen/collection_spec.rb +78 -0
- data/spec/halogen/configuration_spec.rb +11 -0
- data/spec/halogen/definition_spec.rb +108 -0
- data/spec/halogen/definitions_spec.rb +24 -0
- data/spec/halogen/embeds/definition_spec.rb +23 -0
- data/spec/halogen/embeds_spec.rb +201 -0
- data/spec/halogen/links/definition_spec.rb +68 -0
- data/spec/halogen/links_spec.rb +59 -0
- data/spec/halogen/properties_spec.rb +41 -0
- data/spec/halogen/resource_spec.rb +77 -0
- data/spec/halogen_spec.rb +127 -0
- data/spec/spec_helper.rb +11 -0
- metadata +179 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Halogen::Definitions do
|
6
|
+
let :definitions do
|
7
|
+
Halogen::Definitions.new
|
8
|
+
end
|
9
|
+
|
10
|
+
let :definition do
|
11
|
+
Halogen::Definition.new(:name, {}, nil)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#add' do
|
15
|
+
it 'validates and adds definition' do
|
16
|
+
expect(definitions.keys).to eq([])
|
17
|
+
|
18
|
+
definitions.add(definition)
|
19
|
+
|
20
|
+
expect(definitions.keys).to eq(['Halogen::Definition'])
|
21
|
+
expect(definitions['Halogen::Definition']).to eq([definition])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Halogen::Embeds::Definition do
|
6
|
+
describe '#validate' do
|
7
|
+
it 'returns true with procedure' do
|
8
|
+
result = Halogen::Embeds::Definition.new(:name, {}, proc {}).validate
|
9
|
+
|
10
|
+
expect(result).to eq(true)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'raises exception without procedure' do
|
14
|
+
expect {
|
15
|
+
Halogen::Embeds::Definition.new(:name, {}, nil).validate
|
16
|
+
}.to raise_error do |exception|
|
17
|
+
expect(exception).to be_an_instance_of(Halogen::InvalidDefinition)
|
18
|
+
expect(exception.message).to(
|
19
|
+
eq('Embed name must be defined with a proc'))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Halogen::Embeds do
|
6
|
+
let :klass do
|
7
|
+
Class.new do
|
8
|
+
include Halogen
|
9
|
+
include Halogen::Embeds
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Halogen::Embeds::ClassMethods do
|
14
|
+
it 'adds simple embed definition' do
|
15
|
+
expect(klass.definitions).to receive(:add)
|
16
|
+
|
17
|
+
klass.embed(:foo, {}) { 'bar' }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Halogen::Embeds::InstanceMethods do
|
22
|
+
describe '#embedded' do
|
23
|
+
describe 'when no embeds are defined' do
|
24
|
+
it 'returns empty hash when no embeds are requested' do
|
25
|
+
representer = klass.new
|
26
|
+
|
27
|
+
expect(representer.embedded).to eq({})
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns empty hash when embeds are requested' do
|
31
|
+
representer = klass.new(embed: { foo: true })
|
32
|
+
|
33
|
+
expect(representer.embedded).to eq({})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'when embeds are defined' do
|
38
|
+
before :each do
|
39
|
+
klass.embed(:just_nil, {}) { nil }
|
40
|
+
klass.embed(:non_repr, {}) { 'some object' }
|
41
|
+
klass.embed(:child_repr, {}) { child }
|
42
|
+
|
43
|
+
klass.send(:define_method, :child) do
|
44
|
+
# just build another representer instance to be rendered
|
45
|
+
Class.new { include Halogen }.new
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'returns empty hash when no embeds are requested' do
|
50
|
+
representer = klass.new(embed: {})
|
51
|
+
|
52
|
+
expect(representer.embedded).to eq({})
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'builds embedded resources as expected' do
|
56
|
+
embed_opts = { just_nil: true, non_repr: true, child_repr: true }
|
57
|
+
|
58
|
+
representer = klass.new(embed: embed_opts)
|
59
|
+
|
60
|
+
expect(representer.embedded).to eq(child_repr: {})
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#embedded_child' do
|
66
|
+
let :representer do
|
67
|
+
klass.new
|
68
|
+
end
|
69
|
+
|
70
|
+
let :child_class do
|
71
|
+
Class.new do
|
72
|
+
include Halogen
|
73
|
+
|
74
|
+
property(:foo) { 'bar' }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
let :child do
|
79
|
+
child_class.new
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns nil if value is falsey' do
|
83
|
+
[nil, false, 0].each do |value|
|
84
|
+
expect(representer.embedded_child(:foo, value)).to be_nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe 'when value is an array' do
|
89
|
+
it 'renders children' do
|
90
|
+
array = [child, nil, 0, child, 1]
|
91
|
+
|
92
|
+
result = representer.embedded_child(:embed_key, array)
|
93
|
+
|
94
|
+
expect(result).to eq([{ foo: 'bar' }, { foo: 'bar' }])
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe 'when value is a representer' do
|
99
|
+
it 'renders child' do
|
100
|
+
result = representer.embedded_child(:embed_key, child)
|
101
|
+
|
102
|
+
expect(result).to eq(foo: 'bar')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe '#child_embed_opts' do
|
108
|
+
it 'returns empty options for unknown key' do
|
109
|
+
representer = klass.new
|
110
|
+
|
111
|
+
opts = representer.send(:child_embed_opts, :unknown_key)
|
112
|
+
|
113
|
+
expect(opts).to eq({})
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'returns empty options for known key with no child options' do
|
117
|
+
representer = klass.new(embed: { requested_key: 1 })
|
118
|
+
|
119
|
+
opts = representer.send(:child_embed_opts, 'requested_key')
|
120
|
+
|
121
|
+
expect(opts).to eq({})
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'returns child options for known key with child options' do
|
125
|
+
representer = klass.new(embed: { requested_key: { child_key: 0 } })
|
126
|
+
|
127
|
+
opts = representer.send(:child_embed_opts, 'requested_key')
|
128
|
+
|
129
|
+
expect(opts).to eq(child_key: 0)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'returns deeply nested child options' do
|
133
|
+
representer = klass.new(
|
134
|
+
embed: {
|
135
|
+
requested_key: {
|
136
|
+
child_key: { grandchild_key: { great_grandchild_key: 1 } }
|
137
|
+
}
|
138
|
+
}
|
139
|
+
)
|
140
|
+
|
141
|
+
opts = representer.send(:child_embed_opts, 'requested_key')
|
142
|
+
|
143
|
+
expect(opts).to eq(
|
144
|
+
child_key: { grandchild_key: { great_grandchild_key: 1 } })
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe '#render_child' do
|
149
|
+
let :representer do
|
150
|
+
klass.new
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'returns nil if child is not a representer' do
|
154
|
+
[nil, 1, ''].each do |child|
|
155
|
+
expect(representer.render_child(child, {})).to be_nil
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'renders child representer with correct parent and options' do
|
160
|
+
child = Class.new do
|
161
|
+
include Halogen
|
162
|
+
|
163
|
+
property(:verify_parent) { parent.object_id }
|
164
|
+
property(:verify_opts) { options[:embed] }
|
165
|
+
end.new
|
166
|
+
|
167
|
+
result = representer.render_child(child, foo: 'bar')
|
168
|
+
|
169
|
+
expect(result).to eq(
|
170
|
+
verify_parent: representer.object_id,
|
171
|
+
verify_opts: { foo: 'bar' })
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe '#embed_options' do
|
176
|
+
it 'stringifies top level keys' do
|
177
|
+
representer = klass.new(embed: { some: { options: 1 } })
|
178
|
+
|
179
|
+
expect(representer.embed_options).to eq('some' => { options: 1 })
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe '#embed?' do
|
184
|
+
it 'is true for expected values' do
|
185
|
+
[1, 2, true, '1', '2', 'true', 'yes'].each do |value|
|
186
|
+
representer = klass.new(embed: { foo: value })
|
187
|
+
|
188
|
+
expect(representer.embed?('foo')).to eq(true)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'is false for expected values' do
|
193
|
+
[0, false, '0', 'false'].each do |value|
|
194
|
+
representer = klass.new(embed: { foo: value })
|
195
|
+
|
196
|
+
expect(representer.embed?('foo')).to eq(false)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Halogen::Links::Definition do
|
6
|
+
describe '#validate' do
|
7
|
+
it 'returns true with procedure' do
|
8
|
+
result = Halogen::Links::Definition.new(:name, proc {}).validate
|
9
|
+
|
10
|
+
expect(result).to eq(true)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'raises exception without procedure or explicit value' do
|
14
|
+
expect {
|
15
|
+
Halogen::Links::Definition.new(:name, nil).validate
|
16
|
+
}.to raise_error do |exception|
|
17
|
+
expect(exception).to be_an_instance_of(Halogen::InvalidDefinition)
|
18
|
+
expect(exception.message).to(
|
19
|
+
eq('Link requires either procedure or explicit value'))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '.build_options' do
|
25
|
+
it 'has expected value without options hash' do
|
26
|
+
options = Halogen::Links::Definition.build_options([])
|
27
|
+
|
28
|
+
expect(options).to eq(attrs: {})
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'has expected value with options hash' do
|
32
|
+
options = Halogen::Links::Definition.build_options([foo: 'bar'])
|
33
|
+
|
34
|
+
expect(options).to eq(attrs: {}, foo: 'bar')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'merges attrs from options' do
|
38
|
+
options = Halogen::Links::Definition.build_options([
|
39
|
+
:templated,
|
40
|
+
attrs: { properties: {} },
|
41
|
+
foo: 'bar'])
|
42
|
+
|
43
|
+
expect(options).to(
|
44
|
+
eq(attrs: { properties: {}, templated: true }, foo: 'bar'))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '.build_attrs' do
|
49
|
+
it 'returns empty hash if no keywords are provided' do
|
50
|
+
expect(Halogen::Links::Definition.build_attrs([])).to eq({})
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'builds expected hash with recognized keywords' do
|
54
|
+
attrs = Halogen::Links::Definition.build_attrs([:templated])
|
55
|
+
|
56
|
+
expect(attrs).to eq(templated: true)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'raises exception if unrecognized keyword is included' do
|
60
|
+
expect {
|
61
|
+
Halogen::Links::Definition.build_attrs([:templated, :wat])
|
62
|
+
}.to raise_error do |exception|
|
63
|
+
expect(exception.class).to eq(Halogen::InvalidDefinition)
|
64
|
+
expect(exception.message).to eq('Unrecognized link keyword: wat')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Halogen::Links do
|
6
|
+
let :klass do
|
7
|
+
Class.new { include Halogen }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Halogen::Links::ClassMethods do
|
11
|
+
describe '#link' do
|
12
|
+
describe 'with procedure' do
|
13
|
+
it 'builds simple definition' do
|
14
|
+
link = klass.link(:self) { 'path' }
|
15
|
+
|
16
|
+
expect(link.name).to eq(:self)
|
17
|
+
expect(link.options).to eq(attrs: {})
|
18
|
+
expect(link.procedure.call).to eq('path')
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'builds complex definition' do
|
22
|
+
link = klass.link(
|
23
|
+
:self, :templated, foo: 'foo', attrs: { bar: 'bar' }) { 'path' }
|
24
|
+
|
25
|
+
expect(link.name).to eq(:self)
|
26
|
+
expect(link.options).to eq(
|
27
|
+
foo: 'foo', attrs: { templated: true, bar: 'bar' })
|
28
|
+
expect(link.procedure.call).to eq('path')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'without procedure' do
|
33
|
+
describe 'with explicit value' do
|
34
|
+
it 'builds simple definition' do
|
35
|
+
link = klass.link(:self, value: 'path')
|
36
|
+
|
37
|
+
expect(link.name).to eq(:self)
|
38
|
+
expect(link.options).to eq(attrs: {}, value: 'path')
|
39
|
+
expect(link.procedure).to be_nil
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'builds complex definition' do
|
43
|
+
link = klass.link(
|
44
|
+
:self,
|
45
|
+
:templated,
|
46
|
+
foo: 'foo', attrs: { bar: 'bar' }, value: 'path')
|
47
|
+
|
48
|
+
expect(link.name).to eq(:self)
|
49
|
+
expect(link.options).to eq(
|
50
|
+
foo: 'foo',
|
51
|
+
attrs: { templated: true, bar: 'bar' },
|
52
|
+
value: 'path')
|
53
|
+
expect(link.procedure).to be_nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Halogen::Properties do
|
6
|
+
let :klass do
|
7
|
+
Class.new { include Halogen }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Halogen::Properties::ClassMethods do
|
11
|
+
describe '#property' do
|
12
|
+
it 'defines property 'do
|
13
|
+
expect {
|
14
|
+
klass.property(:foo)
|
15
|
+
}.to change(klass.definitions, :size).by(1)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe Halogen::Properties::InstanceMethods do
|
21
|
+
let :repr do
|
22
|
+
klass.new
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#render' do
|
26
|
+
it 'merges super with rendered properties' do
|
27
|
+
allow(repr).to receive(:properties).and_return(foo: 'bar')
|
28
|
+
|
29
|
+
expect(repr.render).to eq(foo: 'bar')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#properties' do
|
34
|
+
it 'builds properties from definitions' do
|
35
|
+
klass.property(:foo, value: 'bar')
|
36
|
+
|
37
|
+
expect(repr.properties).to eq(foo: 'bar')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Halogen::Resource do
|
6
|
+
let :klass do
|
7
|
+
Class.new do
|
8
|
+
include Halogen
|
9
|
+
include Halogen::Resource
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '.included' do
|
14
|
+
it 'raises error if base is already a collection' do
|
15
|
+
resource_class = Class.new do
|
16
|
+
include Halogen
|
17
|
+
include Halogen::Collection
|
18
|
+
end
|
19
|
+
|
20
|
+
expect {
|
21
|
+
resource_class.send :include, Halogen::Resource
|
22
|
+
}.to raise_error do |exception|
|
23
|
+
expect(exception).to be_an_instance_of(Halogen::InvalidResource)
|
24
|
+
expect(exception.message).to match(/has already defined a collection/i)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe Halogen::Resource::ClassMethods do
|
30
|
+
describe '#define_resource' do
|
31
|
+
it 'defines resource' do
|
32
|
+
klass.define_resource :foo
|
33
|
+
|
34
|
+
expect(klass.resource_name).to eq('foo')
|
35
|
+
expect(klass.new(nil).respond_to?(:foo)).to eq(true)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#property' do
|
40
|
+
it 'returns result of super if procedure is present' do
|
41
|
+
original = proc { 'bar' }
|
42
|
+
|
43
|
+
definition = klass.property(:foo, &original)
|
44
|
+
|
45
|
+
expect(definition.procedure).to eq(original)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns result of super if value is present' do
|
49
|
+
definition = klass.property(:foo, value: 'bar')
|
50
|
+
|
51
|
+
expect(definition.procedure).to be_nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'assigns procedure without original procedure or value' do
|
55
|
+
definition = klass.property(:foo)
|
56
|
+
|
57
|
+
expect(definition.procedure).to be_an_instance_of(Proc)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe Halogen::Resource::InstanceMethods do
|
63
|
+
describe '#initialize' do
|
64
|
+
it 'raises error if resource is not provided' do
|
65
|
+
expect { klass.new }.to raise_error(ArgumentError)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'assigns resource' do
|
69
|
+
resource = double(:resource)
|
70
|
+
|
71
|
+
repr = klass.new(resource)
|
72
|
+
|
73
|
+
expect(repr.instance_variable_get(:@resource)).to eq(resource)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|