skn_utils 2.0.6 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,98 +1,98 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/skn_utils.svg)](http://badge.fury.io/rb/skn_utils)
2
2
 
3
- = SknUtils
4
- Ruby Gem containing a Ruby PORO (Plain Old Ruby Object) that can be instantiated at runtime with an input hash. This library creates
5
- an Object with instance variables and associated getters and setters for Dot or Hash notational access to each instance variable. Additional
6
- instance variables can be added post-create by 'obj.my_new_var = "some value"', or simply assigning it.
3
+ = SknUtils
4
+ ==== SknUtils::NestedResult class; dynamic key/value container
5
+ The intent of this gem is to be a container of data results or key/value pairs, with easy access to its contents, and on-demand transformation back to the hash (#to_hash).
7
6
 
7
+ Ruby Gem containing a Ruby PORO (Plain Old Ruby Object) that can be instantiated at runtime with an input hash. This library creates
8
+ an Object with Dot or Hash notational accessors to each key's value. Additional key/value pairs can be added post-create
9
+ by 'obj.my_new_var = "some value"', or simply assigning it.
8
10
 
9
- The intent of this gem is to be a container of data results, with easy access to its contents with on-demand transformation back to a hash (#to_hash)
10
- for easy serialization using standard ruby Hash serialization methods.
11
+ * Transforms the initialization hash into accessable object instance values, with their keys as method names.
12
+ * If the key's value is also a hash, it too will become an Object.
13
+ * if the key's value is a Array of Hashes, or Array of Arrays of Hashes, each element of the Arrays will become an Object.
14
+ * The current key/value (including nested) pairs are returned via #to_hash or #to_json when and if needed.
11
15
 
12
- * Transforms the initialization hash into object instance variables, with their Keys as the variable names
13
- * If the key's value is also a hash, it too can optionally become an Object.
14
- * if the key's value is a Array of Hashes, each element of the Array can optionally become an Object.
15
-
16
- This nesting action is controlled by the value of the options key ':depth'.
17
- The key :depth defaults to :multi, and has options of :single, :multi, or :multi_with_arrays
18
-
19
- The ability of the resulting Object to be Marshalled(dump/load) can be preserved by merging configuration options
20
- into the input params key ':enable_serialization' set to true. It defaults to false for speed purposes
21
-
22
16
 
23
- === New Features
24
- --------------------------------
17
+ == New Features
18
+ 03/2017 V3.0.0
19
+ Added SknUtils::NestedResult to replace, or be an alternate, to ResultBean, GenericBean, PageControls, ValueBean, and AttributeHelper.
20
+ NestedResult overcome issues with serialization via Marshal and Yaml/Psych.
21
+ NestedResult will properly encode all hash based key/value pairs of input and decodes it via #to_h or #to_json
22
+ NestedResult encodes everything given no matter how deeply its nested, unlike the prior version where you had control over nesting.
23
+
24
+ 10/2016 V2.0.6
25
+ Added an SknUtils::NullObject and SknUtils::nullable?(value) extracted from [Avdi Grimm's Confident Code](https://gist.github.com/jschoolcraft/979827)
26
+ The NullObject class has great all around utility, check out it's specs!
25
27
 
26
28
  08/2016 V2.0.3
27
29
  Added an exploritory ActionService class and RSpec test, triggered by reading [Kamil Lelonek](https://blog.lelonek.me/what-service-objects-are-not-7abef8aa2f99#.p64vudxq4)
28
30
  I don't support his approach, but the CreateTask class caught my attention as a Rubyist.
29
31
 
30
- 12/2015 V2.0
32
+ 12/2015 V2.0
31
33
  All references to ActiveRecord or Rails has been removed to allow use in non-Rails environments
32
34
  as a result serialization is done with standard Ruby Hash serialization methods; by first transforming
33
- object back to a hash using its #to_hash method.
35
+ object back to a hash using its #to_hash method.
34
36
 
35
37
  06/2015 V1.5.1 commit #67ef656
36
38
  Last Version to depend on Rails (ActiveModel) for #to_json and #to_xml serialization
37
39
 
38
40
 
39
- === Configuration Options
40
- --------------------------------
41
-
42
- :enable_serialization = false -- [ true | false ], for speed, omits creation of attr_accessor
43
- :depth = :multi -- [ :single | :multi | :multi_with_arrays ]
44
-
41
+ == Configuration Options
42
+ None required other than initialization hash
45
43
 
46
- === Public Methods
47
- --------------------------------
48
44
 
45
+ == Public Methods
49
46
  Each concrete Class supports the following utility methods:
50
- #depth_level -- returns parsing depth level, see :depth
51
- #serialization_required? -- returns true/false if serialization is enabled
52
- #to_hash -- returns a hash of all user attributes
53
- #to_hash(true) -- returns a hash of all user and internal attributes
47
+ #to_hash -- returns a hash of current key/value pairs, including nested
48
+ #to_json -- returns a json string of current key/value pairs, including nested
49
+ #hash_from(:base_key) -- exports the internal hash starting with this base level key
50
+ #obj.obj2.hash_from(:base) -- exports the internal hash starting from this nested base level key
54
51
  #[] -- returns value of attr, when #[<attr_name_symbol>]
55
52
  #[]=(attr, value) -- assigns value to existing attr, or creates a new key/value pair
56
- #clear_<attr> -- assigns nil to existing attr, when #clear_attr
57
53
  #<attr>? -- detects true/false presence? of attr, and non-blank existance of attr's value; when #address?
58
54
  #<attr> -- returns value of named attribute
59
55
  #<attr> = (value) -- assigns value to existing attr, or creates a new key/value pair
60
- -- Where <attr> is a key value from the initial hash, or a key that was dynamically added
56
+ -- Where <attr> is a key value from the initial hash, or a key that was/will be dynamically added
57
+
58
+
61
59
 
60
+ == Public Components
61
+ SknUtils::NestedResult # >= V 3.0.0 Primary Key/Value Container with Dot/Hash notiation support.
62
62
 
63
- === Public Components
64
- --------------------------------
65
63
 
66
- Inherit from NestedResultBase or instantiate a pre-built Class:
67
- SknUtils::ResultBean # => Not Serializable and follows hash values only.
68
- SknUtils::PageControls # => Serializable and follows hash values and arrays of hashes.
69
- SknUtils::GenericBean # => Serializable and follows hash values only.
70
- or Include AttributeHelpers # => Add getter/setters, and hash notation access to instance vars of any object.
64
+ *** <= V 2.0.6 Depreciated, will be removed in next release ***
65
+
66
+ Inherit from NestedResultBase or instantiate an pre-built Class:
67
+ SknUtils::ResultBean # => Not Serializable and follows hash values only.
68
+ SknUtils::PageControls # => Serializable and follows hash values and arrays of hashes.
69
+ SknUtils::GenericBean # => Serializable and follows hash values only.
70
+ SknUtils::ValueBean # => Serializable and DOES NOT follows hash values.
71
+ or Include SknUtils::AttributeHelpers # => Adds getter/setters, and hash notation access to instance vars of any object.
71
72
 
72
73
 
73
74
  == Basic features include:
74
75
  ```ruby
75
- - provides the hash or dot notation methods of accessing values from object created; i.e
76
- 'obj = SknUtils::ResultBean.new({value1: "some value", value2: {one: 1, two: "two"}})
77
- 'x = obj.value1' or 'x = obj.value2.one'
78
- 'x = obj["value1"]'
79
- 'x = obj[:value1]'
76
+ - provides the hash or dot notation methods of accessing values:
80
77
 
81
- - enables serialization by avoiding the use of ''singleton_class'' methods, #attr_accessor, which breaks Serializers:
82
- Serializer supports #to_hash, and standard Marshall''ing. Notice use of #to_hash to convert object back to a Ruby Hash before
83
- using #to_json and #to_xml; presumed to be methods enabled on the standard Ruby Hash class.
78
+ $ obj = SknUtils::NestedResult.new({value1: "some value", value2: {one: 1, two: "two"}})
79
+ $ x = obj.value1
80
+ $ x = obj.value2.one
81
+ $ x = obj["value1"]
82
+ $ x = obj[:value1]
84
83
 
85
- person = SknUtils::PageControls.new({name: "Bob"})
86
- person.to_hash # => {"name"=>"Bob"}
87
- person.to_hash.to_json # => "{\"name\":\"Bob\"}"
88
- person.to_hash.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<page-controls>\n <name>Bob</name>\n</page-controls>\n"
89
- dmp = Marshal.dump(person) # => "\x04\bo:\x1ASknUtils::PageControls\x06:\n@nameI\"\bBob\x06:\x06ET"
90
- person = Marshal.load(dmp) # => #<SknUtils::PageControls:0x007faede906d40 @name="Bob">
84
+ - enables serialization:
85
+ Internally supports #to_hash and #to_json
91
86
 
92
- ***GenericBean designed to automatically handle the setup for serialization and multi level without arrays
87
+ $ person = SknUtils::NestedResult.new({name: "Bob"})
88
+ $ person.to_hash # => {"name"=>"Bob"}
89
+ $ person.to_json # => "{\"name\":\"Bob\"}"
90
+ $ dmp = Marshal.dump(person) # => "\x04\bo:\x1ASknUtils::NestedResult\x06:\n@nameI\"\bBob\x06:\x06ET"
91
+ $ person2 = Marshal.load(dmp) # => #<SknUtils::NestedResult:0x007faede906d40 @name="Bob">
93
92
 
94
93
  - post create additions:
95
- 'obj = SknUtils::ResultBean.new({value1: "some value", value2: {one: 1, two: "two"}})
94
+
95
+ 'obj = SknUtils::NestedResult.new({value1: "some value", value2: {one: 1, two: "two"}})
96
96
  'x = obj.one' --causes NoMethodError
97
97
  'x = obj.one = 'some other value' --creates a new instance value with accessors
98
98
  'x = obj.one = {key1: 1, two: "two"}' --creates a new ***bean as the value of obj.one
@@ -100,129 +100,94 @@ into the input params key ':enable_serialization' set to true. It defaults to f
100
100
  'y = obj.one[:two] --returns "two"
101
101
  'y = obj.one['two'] --returns "two"
102
102
 
103
- - supports predicates <attr>? and clear_<attr>? method patterns:
104
- 'obj = SknUtils::PageControls.new({name: "Something", phone: "2609998888"})'
105
- 'obj.name?' # => true true or false, like obj.name.present?
106
- 'obj.clear_name' # => nil sets :name to nil
103
+ - supports predicates <attr>? method patterns: target must exist and have a non-empty/valid value
104
+
105
+ $ obj = SknUtils::NestedResult.new({name: "Something", active: false, phone: "2609998888"})'
106
+ $ obj.name?' # => true -- true or false, like obj.name.present?
107
+ $ obj.active? # => true -- your asking if method exist with a valid value, not what the value is!
108
+ $ obj.street? # => false
107
109
  ```
108
110
 
109
- The combination of this NestedResultBase(dot notation class) and AttributeHelpers(hash notation module), produces this effect given the same params hash:
110
111
 
111
- drb = SknUtils::ResultBean.new(params) Basic dot notation: effect of :depth
112
- ---------------------------------------------------- -----------------------------------------------------------------
112
+ == Usage:
113
113
 
114
- (DOES NOT FOLLOW Values) :depth => :single
114
+ * The NestedResult produces these effects when given a params hash;
115
+ * Follow VALUES that are Hashes, Arrays of Hashes, and Arrays of Arrays of Hashes
115
116
  ```ruby
116
- * params = {one: 1, drb.one = 1
117
- two: { one: 1, drb.two = {one: 1, two: 'two}
118
- two: "two" drb.two.two = NoMethodError
119
- },
120
- three: [ {one: 'one', two: 2}, drb.three = [{one: 'one', two: 2},{three: 'three', four: 4}]
121
- {three: 'three', four: 4} drb.three[1] = {three: 'three', four: 4}
122
- ] drb.three[1].four = NoMethodError
123
- }
124
- ```
117
+ drb = SknUtils::NestedResult.new(params) Basic dot notation:
118
+ ---------------------------------------------------- -----------------------------------------------------------------
125
119
 
126
- (Follow VALUES that are Hashes only.) :depth => :multi
127
- ```ruby
128
- * params = {one: 1, drb.one = 1
129
- two: { one: 1, drb.two = <SknUtils::ResultBean>
130
- two: "two" drb.two.two = 'two'
131
- },
132
- three: [ {one: 'one', two: 2}, drb.three = [{one: 'one', two: 2},{three: 'three', four: 4}]
133
- {three: 'three', four: 4} drb.three[1] = {three: 'three', four: 4}
134
- ] drb.three[1].four = NoMethodError
135
- }
136
- ```
137
-
138
- (Follow VALUES that are Hashes and/or Arrays of Hashes) :depth => :multi_with_arrays
139
- ```ruby
140
120
  * params = {one: 1, drb.one = 1
141
- two: { one: 1, drb.two = <SknUtils::ResultBean>
142
- two: "two" drb.two.two = 'two'
143
- },
144
- three: [ {one: 'one', two: 2}, drb.three = [<SknUtils::ResultBean>,<SknUtils::ResultBean>]
145
- {three: 'three', four: 4} drb.three[1] = <SknUtils::ResultBean>
146
- ] drb.three[1].four = 4
147
- }
148
-
121
+ two: { one: 1, two: "two"}, drb.two = <SknUtils::NestedResult>
122
+ drb.two.two = 'two'
123
+
124
+ three: [ {one: 'one', two: 2}, drb.three.first.one = 'one'
125
+ {three: 'three', four: 4} drb.three[1].four = 4
126
+ ], drb.three.last.three = 'three'
127
+
128
+ four: [
129
+ [ {one: 'one', two: 2}, drb.four.first.first.one = 'one'
130
+ {three: 'three', four: 4} ], drb.four.first.last.four = 4
131
+ [ { 5: 'five', 6: 'six'}, drb.four[1][0][5] = 'five' # number keys require hash notation :[]
132
+ {five: '5', six: 6} ] drb.four[1].last.six = 6
133
+ ],
134
+ 'five' => [1, 2, 3] drb.five = [1, 2, 3]
135
+ 6 => 'number key' drb[6] = 'number key'
136
+ }
149
137
  ```
150
- = Usage:
151
138
 
152
- (DOES NOT FOLLOW Values)
139
+ * Expected usage
153
140
  ```ruby
154
- class SmallPackage < SknUtils::NestedResultBase
155
- def initialize(params={})
156
- super( params.merge({depth: :single}) ) # override default of :multi level
157
- end
141
+ result = SknUtils::NestedResult.new({
142
+ success: true,
143
+ message: "",
144
+ payload: {package: 'of key/value pairs from operations'}
145
+ })
146
+ ...
147
+
148
+ if result.success && result.payload.package?
149
+ # do something with result.payload
158
150
  end
159
151
  ```
160
152
 
161
- (Follow VALUES that are Hashes only.)
153
+
154
+ * Wrap additional methods around the core NestedResult feature set
162
155
  ```ruby
163
- class MyPackage < SknUtils::NestedResultBase
164
- # defaults to :multi level
165
- end
166
-
167
- -- or --
168
-
169
- class MyPackage < SknUtils::NestedResultBase
156
+ class MyPackage < SknUtils::NestedResult
170
157
  def initialize(params={})
171
- # your other init stuff here
172
- super(params) # default taken
158
+ super
173
159
  end
174
- end
175
-
176
- -- or --
177
-
178
- class MyPackage < SknUtils::NestedResultBase
179
- def initialize(params={})
180
- # your other init stuff here
181
- super( params.merge({depth: :multi}) ) # Specified
182
- end
183
- end
184
-
185
- ** - or -- enable serialization and default to multi
186
- class MyPackage < SknUtils::NestedResultBase
187
- def initialize(params={})
188
- super( params.merge({enable_serialization: true}) ) # Specified with Serialization Enabled
189
- end
190
- end
191
- ```
192
160
 
193
- (Follow VALUES that are Hashes and/or Arrays of Hashes, and enable Serializers)
194
- ```ruby
195
- class MyPackage < SknUtils::NestedResultBase
196
- def initialize(params={})
197
- super( params.merge({depth: :multi_with_arrays, enable_serialization: true}) ) # override defaults
161
+ def additional_method
162
+ # do something
198
163
  end
199
164
  end
200
165
  ```
201
166
 
202
167
 
203
- NOTE: Cannot be Marshalled/Serialized unless input params.merge({enable_serialization: true}) -- default is false
204
- Use GenericBean or PageControls if serialization is needed, they initialize with this value true.
205
-
206
168
  == Installation
207
- ----------------
208
- runtime prereqs:
209
169
 
170
+ runtime prereqs:
171
+ V3+ None
210
172
  V2+ None
211
173
  V1+ gem 'active_model', '~> 3.0'
212
174
 
175
+
213
176
  Add this line to your application's Gemfile:
177
+ ```ruby
178
+ gem 'skn_utils'
179
+ ```
214
180
 
215
- gem 'skn_utils'
216
181
 
217
182
  And then execute:
183
+ $ bundle
218
184
 
219
- $ bundle install
220
185
 
221
186
  Or install it yourself as:
222
-
223
187
  $ gem install skn_utils
224
188
 
225
- == Build
189
+
190
+ == Build
226
191
 
227
192
  1. $ git clone git@github.com:skoona/skn_utils.git
228
193
  2. $ cd skn_utils
@@ -233,27 +198,30 @@ Or install it yourself as:
233
198
  7. $ gem install skn_utils
234
199
  * Done
235
200
 
236
- == Console Workout
201
+
202
+ == Console Workout
237
203
 
238
204
  Start with building gem first.
239
- ```bash
240
- $ cd skn_utils
241
- $ bundle exec pry
242
- [1] pry(main)> require 'active_model'
243
- [2] pry(main)> require 'skn_utils'
244
- [3] pry(main)> rb = SknUtils::ResultBean.new({sample: [{one: "one", two: "two"},{one: 1, two: 2}] })
245
- [4] pry(main)> pg = SknUtils::PageControls.new({sample: [{one: "one", two: "two"},{one: 1, two: 2}] })
246
- [5] pry(main)> pg.sample.first.one # Tip :multi_with_arrays
247
- [6] pry(main)> rb.sample.first.one # Tip :multi without arrays you will get a NoMethodError
248
- [7] pry(main)> rb.sample.first[:one]
249
- ...
250
- [n] pry(main)> exit
251
- * Done
205
+ ```bash
206
+ $ cd skn_utils
207
+ $ bin/console
208
+
209
+ [1] pry(main)> rb = SknUtils::NestedResult.new({sample: [{one: "one", two: "two"},{one: 1, two: 2}] })
210
+ [2] pry(main)> pg = SknUtils::NestedResult.new({sample: [{three: 3, four: 4},{five: 'five', two: 'two'}] })
211
+ [3] pry(main)> pg.sample.first.three
212
+ [4] pry(main)> rb.sample.first.one
213
+ [5] pry(main)> rb.sample.first[:one]
214
+ [6] pry(main)> rb.hash_from(:sample)
215
+ [7] pry(main)> rb.sample?
216
+ [8] pry(main)> rb.sample[0].one?
217
+
218
+ [n] pry(main)> exit
219
+ * Done
252
220
  ```
253
-
221
+
254
222
  == Contributing
255
223
 
256
- 1. Fork it
224
+ 1. Fork it
257
225
  2. Create your feature branch (`git checkout -b my-new-feature`)
258
226
  3. Commit your changes (`git commit -am 'Add some feature'`)
259
227
  4. Push to the branch (`git push origin my-new-feature`)
@@ -262,4 +230,5 @@ Start with building gem first.
262
230
 
263
231
  == License
264
232
 
265
- MIT. See `LICENSE`.
233
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
234
+
data/bin/console ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'skn_utils'
5
+ require 'psych'
6
+
7
+ require 'pry'
8
+ Pry.start
@@ -11,14 +11,14 @@ module SknUtils
11
11
  module_function
12
12
 
13
13
  def option_defaults
14
- @@option_defaults ||= {one: 1, two: 2, three: 3}
14
+ @option_defaults ||= {one: 1, two: 2, three: 3}
15
15
  end
16
16
  def option_defaults=(parms)
17
- @@option_defaults = parms
17
+ @option_defaults = parms
18
18
  end
19
19
 
20
20
  def reset!
21
- @@configuration = Options.new(option_defaults)
21
+ @configuration = Options.new(option_defaults)
22
22
  true
23
23
  end
24
24
 
@@ -27,9 +27,9 @@ module SknUtils
27
27
  end
28
28
 
29
29
  def configure # Initialize with both the configuration keys and default values
30
- @@configuration || reset!
31
- yield(@@configuration) if block_given?
32
- @@configuration
30
+ @configuration || reset!
31
+ yield(@configuration) if block_given?
32
+ @configuration
33
33
  end
34
34
 
35
35
  private