attribute_struct 0.1.2 → 0.1.4

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.
@@ -1,3 +1,10 @@
1
+ ## v0.1.4
2
+ * Add `_array` helper
3
+ * Ensure all helpers are using underscore prefix
4
+ * Inherit from BasicObject
5
+ * Allow struct discovery in enumerable objects
6
+ * Add more helpers
7
+
1
8
  ## v0.1.2
2
9
  * Fix naming in require
3
10
 
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gem 'minitest'
4
+
3
5
  gemspec
@@ -1,16 +1,18 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- attribute_struct (0.1.0)
4
+ attribute_struct (0.1.3)
5
5
  hashie (~> 2.0.5)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
10
  hashie (2.0.5)
11
+ minitest (5.0.6)
11
12
 
12
13
  PLATFORMS
13
14
  ruby
14
15
 
15
16
  DEPENDENCIES
16
17
  attribute_struct!
18
+ minitest
data/README.md CHANGED
@@ -4,6 +4,10 @@ This is a helper library that essentially builds hashes. It
4
4
  wraps hash building with a nice DSL to make it slightly cleaner,
5
5
  more robust, and provide extra features.
6
6
 
7
+ ## Build Status
8
+
9
+ * [![Build Status](https://api.travis-ci.org/chrisroberts/attribute_struct.png)](https://travis-ci.org/chrisroberts/attribute_struct)
10
+
7
11
  ### Usage
8
12
 
9
13
  ```ruby
@@ -1,2 +1,2 @@
1
1
  require 'attribute_struct/version'
2
- require 'attribute_struct/attribute_struct'
2
+
@@ -2,8 +2,8 @@ require 'hashie/extensions/deep_merge'
2
2
  require 'hashie/extensions/indifferent_access'
3
3
 
4
4
  class AttributeStruct
5
- class AttributeHash < Hash
6
- include Hashie::Extensions::DeepMerge
7
- include Hashie::Extensions::IndifferentAccess
5
+ class AttributeHash < ::Hash
6
+ include ::Hashie::Extensions::DeepMerge
7
+ include ::Hashie::Extensions::IndifferentAccess
8
8
  end
9
9
  end
@@ -1,15 +1,20 @@
1
- class AttributeStruct
1
+ class AttributeStruct < BasicObject
2
2
 
3
3
  class << self
4
-
4
+
5
+ # Global flag for camel cased keys
5
6
  attr_reader :camel_keys
7
+ # Force tooling from Chef
6
8
  attr_accessor :force_chef
7
9
 
10
+ # val:: bool
11
+ # Automatically converts keys to camel case
8
12
  def camel_keys=(val)
9
13
  load_the_camels if val
10
14
  @camel_keys = !!val
11
15
  end
12
16
 
17
+ # Loads helpers for camel casing
13
18
  def load_the_camels
14
19
  unless(@camels_loaded)
15
20
  require 'attribute_struct/monkey_camels'
@@ -17,6 +22,7 @@ class AttributeStruct
17
22
  end
18
23
  end
19
24
 
25
+ # Determines what hash library to load based on availability
20
26
  def load_the_hash
21
27
  unless(@hash_loaded)
22
28
  if(defined?(Chef) || force_chef)
@@ -25,34 +31,46 @@ class AttributeStruct
25
31
  else
26
32
  require 'attribute_struct/attribute_hash'
27
33
  end
28
- @hash_loaded
34
+ @hash_loaded = true
29
35
  end
30
36
  end
31
37
 
32
38
  end
33
39
 
40
+ # Flag for camel cased keys
34
41
  attr_reader :_camel_keys
35
42
 
36
43
  def initialize(*args, &block)
37
- self.class.load_the_hash
38
- @_camel_keys = self.class.camel_keys
44
+ _klass.load_the_hash
45
+ @_camel_keys = _klass.camel_keys
39
46
  @table = __hashish.new
40
47
  unless(args.empty?)
41
- if(args.size == 1 && args.first.is_a?(Hash))
48
+ if(args.size == 1 && args.first.is_a?(::Hash))
42
49
  _load(args.first)
43
50
  end
44
51
  end
52
+ if(block)
53
+ self.instance_exec(&block)
54
+ end
45
55
  end
46
56
 
57
+ # val:: bool
58
+ # Turn camel cased keys on/off
47
59
  def _camel_keys=(val)
48
- self.class.load_the_camels if val
60
+ _klass.load_the_camels if val
49
61
  @_camel_keys = !!val
50
62
  end
51
-
63
+
64
+ # key:: Object
65
+ # Access data directly
52
66
  def [](key)
53
67
  _data[_process_key(key)]
54
68
  end
55
69
 
70
+ # key:: Object
71
+ # val:: Object
72
+ # Directly set val into struct. Useful when key is not valid syntax
73
+ # for a ruby method
56
74
  def _set(key, val=nil, &block)
57
75
  if(val)
58
76
  self.method_missing(key, val, &block)
@@ -60,14 +78,15 @@ class AttributeStruct
60
78
  self.method_missing(key, &block)
61
79
  end
62
80
  end
63
-
81
+
82
+ # Dragons and unicorns all over in here
64
83
  def method_missing(sym, *args, &block)
65
84
  if((s = sym.to_s).end_with?('='))
66
85
  s.slice!(-1, s.length)
67
86
  sym = s
68
87
  end
69
88
  sym = _process_key(sym)
70
- @table[sym] ||= AttributeStruct.new
89
+ @table[sym] ||= _klass_new
71
90
  if(!args.empty? || block)
72
91
  if(args.empty? && block)
73
92
  base = @table[sym]
@@ -79,13 +98,13 @@ class AttributeStruct
79
98
  @table[sym] = base
80
99
  elsif(!args.empty? && block)
81
100
  base = @table[sym]
82
- base = self.class.new unless base.is_a?(self.class)
101
+ base = _klass_new unless base.is_a?(_klass)
83
102
  @table[sym] = base
84
103
  leaf = base
85
104
  args.each do |arg|
86
105
  leaf = base[arg]
87
- unless(leaf.is_a?(self.class))
88
- leaf = self.class.new
106
+ unless(leaf.is_a?(_klass))
107
+ leaf = _klass_new
89
108
  base._set(arg, leaf)
90
109
  base = leaf
91
110
  end
@@ -96,36 +115,81 @@ class AttributeStruct
96
115
  leaf.instance_exec(leaf, &block)
97
116
  end
98
117
  else
99
- @table[sym] = args.first
118
+ if(args.size > 1)
119
+ @table[sym] = _klass_new unless @table[sym].is_a?(_klass)
120
+ endpoint = args.inject(@table[sym]) do |memo, k|
121
+ unless(memo[k].is_a?(_klass))
122
+ memo._set(k, _klass_new)
123
+ end
124
+ memo[k]
125
+ end
126
+ return endpoint # custom break out
127
+ else
128
+ @table[sym] = args.first
129
+ end
100
130
  end
101
131
  end
102
132
  @table[sym]
103
133
  end
104
134
 
135
+ # Returns if this struct is considered nil (empty data)
105
136
  def nil?
106
137
  _data.empty?
107
138
  end
108
139
 
140
+ # klass:: Class
141
+ # Returns if this struct is a klass
142
+ def is_a?(klass)
143
+ klass.ancestors.include?(_klass)
144
+ end
145
+ alias_method :kind_of?, :is_a?
146
+
147
+ # Returns current keys within struct
109
148
  def _keys
110
149
  _data.keys
111
150
  end
112
-
151
+
152
+ # Returns underlying data hash
113
153
  def _data
114
154
  @table
115
155
  end
116
156
 
157
+ # key:: Object
158
+ # Delete entry in struct with key
159
+ def _delete(key)
160
+ _data.delete(_process_key(key))
161
+ end
162
+
163
+ # Dumps the current instance to a Hash
117
164
  def _dump
118
- __hashish[
119
- *(@table.map{|key, value|
120
- [key, value.is_a?(self.class) ? value._dump : value]
121
- }.flatten(1))
122
- ]
165
+ processed = @table.map do |key, value|
166
+ if(value.is_a?(::Enumerable))
167
+ flat = value.map do |v|
168
+ v.is_a?(_klass) ? v._dump : v
169
+ end
170
+ val = value.is_a?(::Hash) ? __hashish[*flat.flatten(1)] : flat
171
+ elsif(value.is_a?(_klass))
172
+ val = value._dump
173
+ else
174
+ val = value
175
+ end
176
+ [key, val]
177
+ end
178
+ __hashish[*processed.flatten(1)]
123
179
  end
124
180
 
181
+ # hashish:: Hash type object
182
+ # Clears current instance data and replaces with provided hash
125
183
  def _load(hashish)
126
184
  @table.clear
127
185
  hashish.each do |key, value|
128
- if(value.is_a?(Hash))
186
+ if(value.is_a?(::Enumerable))
187
+ flat = value.map do |v|
188
+ v.is_a?(::Hash) ? _klass.new(v) : v
189
+ end
190
+ value = value.is_a?(::Hash) ? __hashish[*flat.flatten(1)] : flat
191
+ end
192
+ if(value.is_a?(::Hash))
129
193
  self._set(key)._load(value)
130
194
  else
131
195
  self._set(key, value)
@@ -134,60 +198,124 @@ class AttributeStruct
134
198
  self
135
199
  end
136
200
 
201
+ # target:: AttributeStruct
202
+ # Performs a deep merge and returns the resulting AttributeStruct
137
203
  def _merge(target)
138
- source = deep_copy
139
- dest = target.deep_copy
140
- if(defined?(Mash))
141
- result = Chef::Mixin::DeepMerge.merge(source, dest)
204
+ source = _deep_copy
205
+ dest = target._deep_copy
206
+ if(defined?(::Mash))
207
+ result = ::Chef::Mixin::DeepMerge.merge(source, dest)
142
208
  else
143
209
  result = source.deep_merge(dest)
144
210
  end
145
- AttributeStruct.new(result)
211
+ _klass.new(result)
146
212
  end
147
213
 
214
+ # target:: AttributeStruct
215
+ # Performs a deep merge and updates the current instance with the
216
+ # resulting value
148
217
  def _merge!(target)
149
218
  result = _merge(target)._dump
150
219
  _load(result)
151
220
  self
152
221
  end
153
-
222
+
223
+ # Returns a new Hash type instance based on what is available
154
224
  def __hashish
155
- defined?(Mash) ? Mash : AttributeHash
225
+ defined?(::Mash) ? ::Mash : ::AttributeStruct::AttributeHash
156
226
  end
157
-
158
- def do_dup(v)
227
+
228
+ # Returns dup of value. Converts Symbol objects to strings
229
+ def _do_dup(v)
159
230
  begin
160
231
  v.dup
161
232
  rescue
162
- v.is_a?(Symbol) ? v.to_s : v
233
+ v.is_a?(::Symbol) ? v.to_s : v
163
234
  end
164
235
  end
165
236
 
166
- def deep_copy(thing=nil)
237
+ # thing:: Object
238
+ # Returns a proper deep copy
239
+ def _deep_copy(thing=nil)
167
240
  thing ||= _dump
168
- if(thing.is_a?(Enumerable))
169
- val = thing.map{|v| v.is_a?(Enumerable) ? deep_copy(v) : do_dup(v) }
241
+ if(thing.is_a?(::Enumerable))
242
+ val = thing.map{|v| v.is_a?(::Enumerable) ? _deep_copy(v) : _do_dup(v) }
170
243
  else
171
- val = do_dup(thing)
244
+ val = _do_dup(thing)
172
245
  end
173
- if(thing.is_a?(Hash))
246
+ if(thing.is_a?(::Hash))
174
247
  val = __hashish[*val.flatten(1)]
175
248
  end
176
249
  val
177
250
  end
178
251
 
179
- def _process_key(key)
252
+ # key:: String or Symbol
253
+ # Processes the key and returns value based on current settings
254
+ def _process_key(key, *args)
180
255
  key = key.to_s
181
- if(_camel_keys && key._camel?)
256
+ if(_camel_keys && _camel_keys_action)
257
+ case _camel_keys_action
258
+ when :auto_disable
259
+ key._no_hump
260
+ when :auto_enable
261
+ key._hump
262
+ end
263
+ end
264
+ if((_camel_keys && key._camel?) || args.include?(:force))
182
265
  key.to_s.split('_').map do |part|
183
266
  "#{part[0,1].upcase}#{part[1,part.size]}"
184
267
  end.join.to_sym
185
268
  else
186
269
  if(_camel_keys)
187
270
  # Convert so Hash doesn't make a new one and lose the meta
188
- key = CamelString.new(key) unless key.is_a?(CamelString)
271
+ key = ::CamelString.new(key) unless key.is_a?(::CamelString)
189
272
  end
190
273
  key
191
274
  end
192
275
  end
276
+
277
+ # Helper to return class of current instance
278
+ def _klass
279
+ ::AttributeStruct
280
+ end
281
+ alias_method :class, :_klass
282
+
283
+ # Helper to return new instance of current instance type
284
+ def _klass_new
285
+ n = _klass.new
286
+ n._camel_keys_set(_camel_keys_action)
287
+ n
288
+ end
289
+
290
+ # v:: Symbol (:auto_disable, :auto_enable)
291
+ # Sets custom rule for processed keys
292
+ def _camel_keys_set(v)
293
+ @_camel_keys_set = v
294
+ end
295
+
296
+ # Returns value set via #_camel_keys_set
297
+ def _camel_keys_action
298
+ @_camel_keys_set
299
+ end
300
+
301
+ # args:: Objects
302
+ # Helper to create Arrays with nested AttributeStructs. Proc
303
+ # instances are automatically executed into new AttributeStruct
304
+ # instances
305
+ def _array(*args)
306
+ args.map do |maybe_block|
307
+ if(maybe_block.is_a?(::Proc))
308
+ klass = _klass_new
309
+ if(maybe_block.arity > 0)
310
+ klass.instance_exec(klass, &maybe_block)
311
+ else
312
+ klass.instance_exec(&maybe_block)
313
+ end
314
+ klass
315
+ else
316
+ maybe_block
317
+ end
318
+ end
319
+ end
320
+
193
321
  end
@@ -1,6 +1,8 @@
1
+ require 'attribute_struct/attribute_struct'
2
+
1
3
  class AttributeStruct
2
- class Version < Gem::Version
4
+ class Version < ::Gem::Version
3
5
  end
4
6
 
5
- VERSION = Version.new('0.1.2')
7
+ VERSION = Version.new('0.1.4')
6
8
  end
@@ -0,0 +1,3 @@
1
+ Dir.glob(File.join(File.expand_path(File.dirname(__FILE__)), 'specs/*.rb')).each do |path|
2
+ require path
3
+ end
@@ -0,0 +1,169 @@
1
+ require 'minitest/autorun'
2
+
3
+ describe AttributeStruct do
4
+ describe 'Basic usage' do
5
+ describe 'instance based population' do
6
+ before do
7
+ @struct = AttributeStruct.new
8
+ @struct.method.based.access true
9
+ @struct.method('and', 'parameter', 'based').access true
10
+ @struct.block do
11
+ based.access true
12
+ end
13
+ @struct.block('and', 'parameter', 'based') do
14
+ access true
15
+ end
16
+ @struct.block_only do
17
+ access true
18
+ end
19
+ @struct._set('1') do
20
+ value true
21
+ end
22
+ end
23
+
24
+ it 'allows method based access' do
25
+ @struct.method.based.access.must_equal true
26
+ end
27
+
28
+ it 'allows method and parameter based access' do
29
+ @struct.method.and.parameter.based.access.must_equal true
30
+ end
31
+
32
+ it 'allows block based access' do
33
+ @struct.block.based.access.must_equal true
34
+ end
35
+
36
+ it 'allows block and parameter based access' do
37
+ @struct.block.and.parameters.based.access.must_equal true
38
+ end
39
+
40
+ it 'allows block only access' do
41
+ @struct.block_only.access.must_equal true
42
+ end
43
+
44
+ it 'allows hash style access' do
45
+ @struct['method'][:based].access.must_equal true
46
+ end
47
+
48
+ it 'allows _set for invalid method names' do
49
+ @struct['1'].value.must_equal true
50
+ end
51
+ end
52
+
53
+ describe 'block based creation' do
54
+ before do
55
+ @struct = AttributeStruct.new do
56
+ enable true
57
+ access.user true
58
+ access do
59
+ port 80
60
+ transport :udp
61
+ end
62
+ end
63
+ end
64
+
65
+ it 'creates struct with block content' do
66
+ @struct.enable.must_equal true
67
+ @struct.access.user.must_equal true
68
+ @struct.access.port.must_equal 80
69
+ @struct.access.transport.must_equal :udp
70
+ end
71
+
72
+ end
73
+
74
+ describe 'nil behavior' do
75
+ before do
76
+ @struct = AttributeStruct.new
77
+ end
78
+
79
+ it 'should return as nil' do
80
+ @struct.must_be_nil
81
+ end
82
+ end
83
+
84
+ describe 'array helper' do
85
+ before do
86
+ @struct = AttributeStruct.new do
87
+ my_array _array(
88
+ -> {
89
+ working true
90
+ },
91
+ :item
92
+ )
93
+ end
94
+ end
95
+
96
+ it 'should contain an array at my_array' do
97
+ @struct.my_array.must_be_kind_of Array
98
+ end
99
+
100
+ it 'should contain symbol in array' do
101
+ @struct.my_array.must_include :item
102
+ end
103
+
104
+ it 'should contain an AttrubuteStruct instance in array' do
105
+ assert @struct.my_array.detect{|i| i.is_a?(AttributeStruct)}
106
+ end
107
+
108
+ it 'should contain working attribute in array struct' do
109
+ @struct.my_array.detect{|i| i.is_a?(AttributeStruct)}.working.must_equal true
110
+ end
111
+ end
112
+
113
+ describe 'entry deletion' do
114
+ before do
115
+ @struct = AttributeStruct.new do
116
+ value1 true
117
+ value2 true
118
+ end
119
+ @struct._delete(:value2)
120
+ end
121
+
122
+ it 'should contain value1' do
123
+ @struct.value1.must_equal true
124
+ end
125
+
126
+ it 'should not contain value2 in keys' do
127
+ @struct._keys.wont_include 'value2'
128
+ end
129
+
130
+ it 'should report nil for value2' do
131
+ @struct.value2.must_be_nil
132
+ end
133
+ end
134
+
135
+ describe 'dumps' do
136
+ before do
137
+ @struct = AttributeStruct.new do
138
+ value1 true
139
+ value2 do
140
+ nested true
141
+ end
142
+ end
143
+ end
144
+
145
+ it 'should dump to a hash type value' do
146
+ @struct._dump.must_be_kind_of Hash
147
+ end
148
+
149
+ it 'should include all defined values' do
150
+ dump = @struct._dump
151
+ dump['value1'].must_equal true
152
+ dump['value2'].must_be_kind_of Hash
153
+ dump['value2']['nested'].must_equal true
154
+ end
155
+ end
156
+
157
+ describe 'loads' do
158
+ before do
159
+ @hash = {'value1' => true, 'value2' => {'nested' => true}}
160
+ @struct = AttributeStruct.new(@hash)
161
+ end
162
+
163
+ it 'should include all values defined in hash' do
164
+ @struct.value1.must_equal true
165
+ @struct.value2.nested.must_equal true
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,43 @@
1
+ require 'minitest/autorun'
2
+
3
+ describe AttributeStruct do
4
+ describe 'Camel usage' do
5
+ before do
6
+ AttributeStruct.camel_keys = true
7
+ @struct = AttributeStruct.new do
8
+ value_one true
9
+ value_two do
10
+ nesting true
11
+ end
12
+ end
13
+ end
14
+ after do
15
+ AttributeStruct.camel_keys = false
16
+ end
17
+
18
+ it 'should camel case keys when dumped' do
19
+ @struct._dump.keys.must_include 'ValueOne'
20
+ @struct._dump.keys.must_include 'ValueTwo'
21
+ end
22
+
23
+ it 'should allow explicit disable on keys' do
24
+ @struct._set('not_camel'._no_hump, true)
25
+ @struct._dump.keys.must_include 'not_camel'
26
+ end
27
+
28
+ it 'should allow implicit disable on nested structs' do
29
+ @struct.disable_camel do |struct|
30
+ struct._camel_keys_set(:auto_disable)
31
+ not_camel true
32
+ not_camel_nest do
33
+ no_camel_here true
34
+ end
35
+ end
36
+ dump = @struct._dump
37
+ dump['DisableCamel'][:not_camel].must_equal true
38
+ dump['DisableCamel'][:not_camel_nest][:no_camel_here].must_equal true
39
+ dump['ValueOne'].must_equal true
40
+ dump['ValueTwo']['Nesting'].must_equal true
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,55 @@
1
+ require 'minitest/autorun'
2
+
3
+ describe AttributeStruct do
4
+ describe 'Merging usage' do
5
+ before do
6
+ @struct1 = AttributeStruct.new do
7
+ value1 true
8
+ value2 do
9
+ nesting true
10
+ end
11
+ end
12
+ @struct2 = AttributeStruct.new do
13
+ value2 do
14
+ nesting false
15
+ squashing true
16
+ end
17
+ end
18
+ end
19
+
20
+ describe 'new struct from merge' do
21
+ before do
22
+ @struct = @struct1._merge(@struct2)
23
+ end
24
+
25
+ it 'should have correct value for value1' do
26
+ @struct.value1.must_equal true
27
+ end
28
+
29
+ it 'should have correct value for squashing' do
30
+ @struct.value2.squashing.must_equal true
31
+ end
32
+
33
+ it 'should have correct value for nesting' do
34
+ @struct.value2.nesting.must_equal false
35
+ end
36
+ end
37
+
38
+ describe 'update struct from merge' do
39
+ before do
40
+ @struct = AttributeStruct.new do
41
+ test_value true
42
+ end
43
+ @struct._merge!(@struct1)
44
+ end
45
+
46
+ it 'should contain test_value' do
47
+ @struct.test_value.must_equal true
48
+ end
49
+
50
+ it 'should contain value1' do
51
+ @struct.value1.must_equal true
52
+ end
53
+ end
54
+ end
55
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attribute_struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-08 00:00:00.000000000 Z
12
+ date: 2013-07-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: hashie
@@ -38,9 +38,12 @@ files:
38
38
  - lib/attribute_struct/version.rb
39
39
  - lib/attribute_struct/attribute_hash.rb
40
40
  - lib/attribute_struct/monkey_camels.rb
41
+ - test/spec.rb
42
+ - test/specs/camel.rb
43
+ - test/specs/merging.rb
44
+ - test/specs/basic.rb
41
45
  - Gemfile
42
46
  - README.md
43
- - attribute_struct-0.1.0.gem
44
47
  - attribute_struct.gemspec
45
48
  - CHANGELOG.md
46
49
  - Gemfile.lock
Binary file