attribute_struct 0.2.28 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 41547b7309813fb1da48c6e17e0d063215d08963
4
- data.tar.gz: 9ebfd315aab3eecc4a92d6a08c3276bddd9538ba
3
+ metadata.gz: 8589e76432a36f05a1450f97e802269ef8edb8df
4
+ data.tar.gz: 6364945c9d3ccb645eb54e2a419675a7d4f2ad61
5
5
  SHA512:
6
- metadata.gz: bb2c29323b1d75a607f097d49e79e5f91649810ae7c066651c09cd890fbe6c0c0266df29930d16c8f8cd5887345dcb9169064cbeb3145d129ca6742590c7194f
7
- data.tar.gz: bfd1e337210551aea3a1c090ba09b84431b44a1f90d0eaa88d6e25fbfa4412289b6af1400dfb95cb255661d5e17ab3154c0c0f06bc584086bd127da4444e30ab
6
+ metadata.gz: 1bf46e3d433e2718593b6981303a88226b38aff6b421028d1b23f79fb7bdf765a7f800a2c0d35a4d33323f17f3a2a33f73b201d8aee88fec0b68aa1b4757d8b6
7
+ data.tar.gz: e26b766049f6bd19ba1b9e54bae280ae97372d5b438ee15bd1c44f97d8d20b2c802461a9f14721a3eaa98ee65f83f9a4a412fbe2faee590b4b980ff97aed05e1
data/CHANGELOG.md CHANGED
@@ -1,80 +1,85 @@
1
- ## v0.2.28
1
+ # v0.3.0
2
+ * Only allow forced key processing when camel casing is enabled
3
+ * Refactored dump implementation to better handle deeply nested structs
4
+ * Add missing bang method aliases
5
+
6
+ # v0.2.28
2
7
  * Set internal data at creation time, not after evaluation
3
8
 
4
- ## v0.2.26
9
+ # v0.2.26
5
10
  * Add support for lowercase leading camel casing
6
11
 
7
- ## v0.2.24
12
+ # v0.2.24
8
13
  * Fix `#_root` helper to properly check for parent
9
14
  * Always use the `#_klass_new` helper
10
15
  * Support optional arguments/block to `#_klass_new`
11
16
 
12
- ## v0.2.22
17
+ # v0.2.22
13
18
  * Add more helper method bang aliases
14
19
  * Properly persist camel data on Hash keys
15
20
  * Support optional automatic AttributeStruct loading on Hash set
16
21
 
17
- ## v0.2.20
22
+ # v0.2.20
18
23
  * Fix: remove nil structs
19
24
 
20
- ## v0.2.18
25
+ # v0.2.18
21
26
  * Fix `AttributeStruct#dump!` to properly handle nil-type values
22
27
 
23
- ## v0.2.16
28
+ # v0.2.16
24
29
  * Fix regression mixed argument and block set returning second level struct
25
30
 
26
- ## v0.2.14
31
+ # v0.2.14
27
32
  * Fix `:value_collapse` option to prevent multiple nestings
28
33
 
29
- ## v0.2.12
34
+ # v0.2.12
30
35
  * Implementation updates to monkey camels helper
31
36
  * Provide bang style helper methods for all helpers
32
37
 
33
- ## v0.2.10
38
+ # v0.2.10
34
39
  * Add support for multi parameter set
35
40
 
36
- ## v0.2.8
41
+ # v0.2.8
37
42
  * Fix class mismatch issue
38
43
 
39
- ## v0.2.6
44
+ # v0.2.6
40
45
  * Vendor `Mash` and expand to provide required deep_merge functionality
41
46
  * Remove external dependencies
42
47
 
43
- ## v0.2.4
48
+ # v0.2.4
44
49
  * Revert #class method removal (required by hash helpers when duping)
45
50
  * Set base prior to path walking
46
51
  * Initialize struct if nil is encountered
47
52
  * Collapse values at leaf
48
53
 
49
- ## v0.2.2
54
+ # v0.2.2
50
55
  * Update block evaluation assignment to prevent value knockout
51
56
  * Fix `#is_a?` behavior and include base class in check list
52
57
  * Add `#respond_to?` method
53
58
  * Add irb helper module
54
59
 
55
- ## v0.2.0
60
+ # v0.2.0
56
61
  * Add support for value setting into given context level
57
62
  * Add #build helper method
58
63
  * Introduce `:value_collapse` option for multi set combination instead of replacement
59
64
  * Provide bang suffix aliases
60
65
 
61
- ## v0.1.8
66
+ # v0.1.8
62
67
  * Basic (optional) auto camel detection on import
63
68
  * Add hash helper methods out to class
64
69
 
65
- ## v0.1.6
70
+ # v0.1.6
66
71
  * Add helpers for walking up the tree
67
72
  * Update hashie dependency restriction
68
73
 
69
- ## v0.1.4
74
+ # v0.1.4
70
75
  * Add `_array` helper
71
76
  * Ensure all helpers are using underscore prefix
72
77
  * Inherit from BasicObject
73
78
  * Allow struct discovery in enumerable objects
74
79
  * Add more helpers
75
80
 
76
- ## v0.1.2
81
+ # v0.1.2
77
82
  * Fix naming in require
78
83
 
79
- ## v0.1.0
84
+ # v0.1.0
80
85
  * Initial release
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2014 Chris Roberts
1
+ Copyright 2016 Chris Roberts
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -1,66 +1,256 @@
1
1
  # AttributeStruct
2
2
 
3
- This is a helper library that essentially builds hashes. It
4
- wraps hash building with a nice DSL to make it slightly cleaner,
5
- more robust, and provide extra features.
3
+ AttributeStruct is a DSL helper library. It provides support for programmatic
4
+ generation of complex data structures.
6
5
 
7
- ## Build Status
6
+ ## How it works
8
7
 
9
- * [![Build Status](https://api.travis-ci.org/chrisroberts/attribute_struct.png)](https://travis-ci.org/chrisroberts/attribute_struct)
8
+ Under the hood, AttributeStruct makes use of Ruby's `BasicObject` class and the
9
+ `#method_missing` method to bring a clean and concise way of generating data
10
+ structures. Deeply nested Hashes can be built using method chaining, block
11
+ structures, or both. Evaluation of a structure is performed top down, allowing
12
+ access to previously set data values within the structure during evaluation.
10
13
 
11
- ## Usage
14
+ ## Examples
15
+
16
+ ### Setting values
17
+
18
+ #### Method chaining
19
+
20
+ ```ruby
21
+ require 'attribute_struct'
22
+
23
+ AttributeStruct.new do
24
+ this.is.a.deeply.nested.hash true
25
+ end.dump!
26
+
27
+ # => {"this"=>{"is"=>{"a"=>{"deeply"=>{"nested"=>{"hash"=>true}}}}}}
28
+ ```
29
+
30
+ #### Block nesting
31
+
32
+ ```ruby
33
+ require 'attribute_struct'
34
+
35
+ AttributeStruct.new do
36
+ this do
37
+ is do
38
+ a do
39
+ deeply do
40
+ nested do
41
+ hash true
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end.dump!
48
+
49
+ # => {"this"=>{"is"=>{"a"=>{"deeply"=>{"nested"=>{"hash"=>true}}}}}}
50
+ ```
51
+
52
+ #### Mixed block nesting and method chaining
53
+
54
+ ```ruby
55
+ require 'attribute_struct'
56
+
57
+ AttributeStruct.new do
58
+ this.is.a do
59
+ deeply.nested do
60
+ hash true
61
+ end
62
+ end
63
+ end.dump!
64
+
65
+ # => {"this"=>{"is"=>{"a"=>{"deeply"=>{"nested"=>{"hash"=>true}}}}}}
66
+ ```
67
+
68
+ ### Structure re-entry
69
+
70
+ #### Block re-entry
71
+
72
+ ```ruby
73
+ require 'attribute_struct'
74
+
75
+ AttributeStruct.new do
76
+ this.is.a do
77
+ deeply.nested do
78
+ hash true
79
+ end
80
+ deeply do
81
+ nested.other_hash true
82
+ end
83
+ end
84
+ end.dump!
85
+
86
+ # => {"this"=>{"is"=>{"a"=>{"deeply"=>{"nested"=>{"hash"=>true,"other_hash"=>true}}}}}}
87
+ ```
88
+
89
+ #### Method re-entry
90
+
91
+ ```ruby
92
+ require 'attribute_struct'
93
+
94
+ AttributeStruct.new do
95
+ this.is.a do
96
+ deeply.nested do
97
+ hash true
98
+ end
99
+ end
100
+ this.is.a.deeply.nested.other_hash true
101
+ end.dump!
102
+
103
+ # => {"this"=>{"is"=>{"a"=>{"deeply"=>{"nested"=>{"hash"=>true,"other_hash"=>true}}}}}}
104
+ ```
105
+
106
+ ### Data removal
107
+
108
+ ```ruby
109
+ require 'attribute_struct'
110
+
111
+ AttributeStruct.new do
112
+ this.is.a do
113
+ deeply.nested do
114
+ hash true
115
+ end
116
+ end
117
+ this.is.a.deeply.nested.other_hash true
118
+ this.is.a.deeply.nested.delete!(:hash)
119
+ end.dump!
120
+
121
+ # => {"this"=>{"is"=>{"a"=>{"deeply"=>{"nested"=>{"other_hash"=>true}}}}}}
122
+ ```
123
+
124
+ ### Data Access
125
+
126
+ #### Current data
127
+
128
+ ```ruby
129
+ require 'attribute_struct'
130
+
131
+ AttributeStruct.new do
132
+ this.is.a do
133
+ deeply.nested do
134
+ hash 'my_value'
135
+ end
136
+ end
137
+ this.is.a.deeply.nested do
138
+ other_hash data![:hash]
139
+ end
140
+ end.dump!
141
+
142
+ # => {"this"=>{"is"=>{"a"=>{"deeply"=>{"nested"=>{"hash"=>"my_value","other_hash"=>"my_value"}}}}}}
143
+ ```
144
+
145
+ #### Current data keys
12
146
 
13
147
  ```ruby
14
148
  require 'attribute_struct'
15
149
 
16
- struct = AttributeStruct.new
17
- struct.settings do
18
- ui.admin do
19
- enabled true
20
- port 8080
21
- bind '*'
150
+ AttributeStruct.new do
151
+ this.is.a do
152
+ deeply.nested do
153
+ hash 'my_value'
154
+ end
22
155
  end
23
- ui.public do
24
- enabled true
25
- port 80
26
- bind '*'
156
+ this.is.a.deeply.nested do
157
+ other_hash keys!
27
158
  end
28
- client('general') do
29
- enabled false
159
+ end.dump!
160
+
161
+ # => {"this"=>{"is"=>{"a"=>{"deeply"=>{"nested"=>{"hash"=>"my_value","other_hash"=>["hash"]}}}}}}
162
+ ```
163
+
164
+ ### Hierarchy access
165
+
166
+ #### Parent structure
167
+
168
+ ```ruby
169
+ require 'attribute_struct'
170
+
171
+ AttributeStruct.new do
172
+ this.is.a do
173
+ deeply do
174
+ state 'sunny'
175
+ nested do
176
+ hash parent!.state
177
+ end
178
+ end
30
179
  end
31
- end
180
+ end.dump!
181
+
182
+ # => {"this"=>{"is"=>{"a"=>{"deeply"=>{"state"=>"sunny", "nested"=>{"hash"=>"sunny"}}}}}}
32
183
  ```
33
184
 
34
- Now we have an attribute structure that we can
35
- query and modify. To force it to a hash, we
36
- can simply dump it:
185
+ #### Root structure
37
186
 
38
187
  ```ruby
39
- require 'pp'
188
+ require 'attribute_struct'
189
+
190
+ AttributeStruct.new do
191
+ this.is.a do
192
+ deeply do
193
+ state 'sunny'
194
+ nested do
195
+ hash root!.this.is.a.deeply.state
196
+ end
197
+ end
198
+ end
199
+ end.dump!
40
200
 
41
- pp struct._dump
201
+ # => {"this"=>{"is"=>{"a"=>{"deeply"=>{"state"=>"sunny", "nested"=>{"hash"=>"sunny"}}}}}}
42
202
  ```
43
203
 
44
- which gives:
204
+ ### Camel case
205
+
206
+ #### Camel case keys
45
207
 
46
208
  ```ruby
47
- {"settings"=>
48
- {"ui"=>
49
- {"admin"=>{"enabled"=>true, "port"=>8080, "bind"=>"*"},
50
- "public"=>{"enabled"=>true, "port"=>80, "bind"=>"*"}},
51
- "client"=>{"general"=>{"enabled"=>false}}}}
209
+ require 'attribute_struct'
210
+
211
+ AttributeStruct.new do
212
+ self._camel_keys = true
213
+ this.is.a.deeply.nested_camel.hash true
214
+ end.dump!
215
+
216
+ # => {"This"=>{"Is"=>{"A"=>{"Deeply"=>{"NestedCamel"=>{"Hash"=>true}}}}}}
52
217
  ```
53
218
 
54
- ## IRB
219
+ #### Camel case with lead lower
220
+
221
+ ```ruby
222
+ require 'attribute_struct'
223
+
224
+ AttributeStruct.new do
225
+ self._camel_keys = true
226
+ self._camel_style = :no_leading
227
+ this.is.a.deeply.nested_camel.hash true
228
+ end.dump!
55
229
 
56
- IRB expects some things to be around like `#inspect` and `#to_s`. Before
57
- using `AttributeStruct` in IRB, enable compat mode:
230
+ # => {"this"=>{"is"=>{"a"=>{"deeply"=>{"nestedCamel"=>{"hash"=>true}}}}}}
231
+ ```
232
+
233
+ #### Disable camel on individual key
58
234
 
59
235
  ```ruby
60
- > require 'attribute_struct'
61
- > AttributeStruct.irb_compat!
236
+ require 'attribute_struct'
237
+
238
+ AttributeStruct.new do
239
+ self._camel_keys = true
240
+ this.is.a.deeply.nested_camel.hash true
241
+ this.set!('horse'.no_hump!, true)
242
+ end.dump!
243
+
244
+ # => {"This"=>{"Is"=>{"A"=>{"Deeply"=>{"NestedCamel"=>{"Hash"=>true}}}}},"horse" => true}
62
245
  ```
63
246
 
247
+ ## In the wild
248
+
249
+ Libraries utilizing AttributeStruct:
250
+
251
+ * SparkleFormation: http://www.sparkleformation.io
252
+ * Bogo Config: https://github.com/spox/bogo-config
253
+
64
254
  ## Information
65
255
 
66
256
  * Repo: https://github.com/chrisroberts/attribute_struct
@@ -8,7 +8,7 @@ class AttributeStruct < BasicObject
8
8
 
9
9
  # @return [Hash] valid styles and mapped value
10
10
  VALID_CAMEL_STYLES = {
11
- :bactrain => :no_leading,
11
+ :bactrian => :no_leading,
12
12
  :no_leading_hump => :no_leading,
13
13
  :no_leading => :no_leading,
14
14
  :dromedary => :leading,
@@ -87,10 +87,13 @@ class AttributeStruct < BasicObject
87
87
 
88
88
  # @return [Truthy, Falsey] current camelizing setting
89
89
  attr_reader :_camel_keys
90
+ alias_method :camel_keys!, :_camel_keys
90
91
  # @return [Symbol] current camel style
91
92
  attr_reader :_camel_style
93
+ alias_method :camel_style!, :_camel_style
92
94
  # @return [AtributeStruct::AttributeHash, Mash] holding space for state
93
95
  attr_reader :_arg_state
96
+ alias_method :arg_state!, :_arg_state
94
97
 
95
98
  # Create new instance
96
99
  #
@@ -300,6 +303,11 @@ class AttributeStruct < BasicObject
300
303
  _data.empty?
301
304
  end
302
305
 
306
+ # @return [TrueClass, FalseClass] struct is present (not empty)
307
+ def present?
308
+ !nil?
309
+ end
310
+
303
311
  # Determine if self is a class
304
312
  #
305
313
  # @param klass [Class]
@@ -330,22 +338,39 @@ class AttributeStruct < BasicObject
330
338
  end
331
339
  alias_method :delete!, :_delete
332
340
 
333
- # @return [AttributeStruct::AttributeHash, Mash] dump struct to hashish
334
- def _dump
335
- processed = @table.map do |key, value|
336
- if(value.is_a?(::Enumerable))
337
- flat = value.map do |v|
338
- v.is_a?(_klass) ? v._dump : v
339
- end
340
- val = value.is_a?(::Hash) ? __hashish[*flat.flatten(1)] : flat
341
- elsif(value.is_a?(_klass) && value.nil?)
342
- next
343
- elsif(value.is_a?(_klass) && !value.nil?)
344
- val = value._dump
341
+ # Process and unpack items for dumping within deeply nested
342
+ # enumerable types
343
+ #
344
+ # @param item [Object]
345
+ # @return [Object]
346
+ def _dump_unpacker(item)
347
+ if(item.is_a?(::Enumerable))
348
+ if(item.respond_to?(:keys))
349
+ item.class[
350
+ *item.map do |entry|
351
+ _dump_unpacker(entry)
352
+ end.flatten(1)
353
+ ]
345
354
  else
346
- val = value.nil? ? nil : value
355
+ item.class[
356
+ *item.map do |entry|
357
+ _dump_unpacker(entry)
358
+ end
359
+ ]
347
360
  end
348
- [key, val]
361
+ elsif(item.is_a?(::AttributeStruct))
362
+ item.nil? ? :__unset__ : item._dump
363
+ else
364
+ item
365
+ end
366
+ end
367
+
368
+ # @return [AttributeStruct::AttributeHash, Mash] dump struct to hashish
369
+ def _dump
370
+ processed = @table.keys.map do |key|
371
+ value = @table[key]
372
+ val = _dump_unpacker(value)
373
+ [_dump_unpacker(key), val] unless val == :__unset__
349
374
  end.compact
350
375
  __hashish[*processed.flatten(1)]
351
376
  end
@@ -453,7 +478,7 @@ class AttributeStruct < BasicObject
453
478
  key._hump
454
479
  end
455
480
  end
456
- if((_camel_keys && key._camel?) || args.include?(:force))
481
+ if(_camel_keys && (key._camel? || args.include?(:force)))
457
482
  camel_args = [key]
458
483
  if(key._hump_style || _camel_style == :no_leading)
459
484
  unless(key._hump_style == :leading_hump)
@@ -73,13 +73,13 @@ unless(defined?(MonkeyCamels))
73
73
  # Set hump style to non-leading upcase
74
74
  #
75
75
  # @return [self]
76
- def _bactrain
76
+ def _bactrian
77
77
  @__not_camel = false
78
78
  @__hump_style = :no_leading_hump
79
79
  self
80
80
  end
81
- alias_method :bactrain!, :_bactrain
82
- alias_method :no_leading_hump!, :_bactrain
81
+ alias_method :bactrian!, :_bactrian
82
+ alias_method :no_leading_hump!, :_bactrian
83
83
 
84
84
  # Set hump style to leading upcase
85
85
  #
@@ -1,4 +1,4 @@
1
1
  class AttributeStruct < BasicObject
2
2
  # Current library version
3
- VERSION = ::Gem::Version.new('0.2.28')
3
+ VERSION = ::Gem::Version.new('0.3.0')
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attribute_struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.28
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Roberts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-30 00:00:00.000000000 Z
11
+ date: 2016-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bogo