hashcraft 1.0.0.pre.alpha.1 → 1.0.0.pre.alpha.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9dfbb2b3856098765290235f1fd1debd3fbd267cac38235e2aa2cf87fe35dac8
4
- data.tar.gz: 41888aa7d9b3f977308d47039a3732d0b5d0973af8ab9bcd45f08ee986408027
3
+ metadata.gz: c70ff2e1bf5cecc91ae33eba7b1fb5810371ab3f67a4f077e02c0dc8a3b6fac8
4
+ data.tar.gz: b116b485b82e3cacc55e7a217d3682a06334a970c105eef95db01f054bf44655
5
5
  SHA512:
6
- metadata.gz: de2140ec7116e7e284e11d7fe11eaa3266b91025f0e2235050492a9eef1bb35ceb88ab7557728acd808516413b25f6a85928e0190a9779a58447f2ef51f78e6f
7
- data.tar.gz: 8a150eefc4294b49d65e7fc950d50a5ce01739c212863546624b3775cf00af5dd5fab320573f8f2a93e86beac53773299506d7de1f3a59affc2274bedd5ab716
6
+ metadata.gz: a03980f411dd97dd6744780fa01a74891f618703faaa3b06c24cd2f088ab387a4127ab17d9c9b0f02c7c746fd0701ee66743d4debee5e4c29f9c8704d03f2cca
7
+ data.tar.gz: e90a7ea856b01fd8298e30a2eef2c1ad81d0337c819792a0df8108145419caa1fe19502502c0a3df17f1e24b792c435b4e7983030dc61cb2d4f310cbb7a639e3
data/.gitignore CHANGED
@@ -4,5 +4,4 @@
4
4
  /coverage
5
5
  Gemfile.lock
6
6
  /pkg
7
-
8
-
7
+ /doc
data/README.md CHANGED
@@ -147,7 +147,7 @@ This means there is an available method called api_url that can be called to set
147
147
  * **eager**: always assign a value. When true it will always assign the key a value.
148
148
  * **key**: allows for aliasing keys. If omitted, the key will be the option's method name (api_url as noted above).
149
149
  * **meta**: used to store any arbitrary data that can be accessed with transformers.
150
- * **mutator**: defines the type of the data backing the method, defaulting to property. When the default property is used then it will simply assign the passed in value. Other values are: `hash` and `array`. When hash is used then the passed in value will be merged onto the key's value. When array is used then the passed in value will be pushed onto the key's value.
150
+ * **mutator**: defines the *type of update* to be made to the underlying value, defaulting to `property`. When the default, `property`, is used then it will simply assign the passed in value. Some other options are: `hash` and `array`. When hash is used then the passed in value will be merged onto the key's value. When array is used then the passed in value will be pushed onto the key's value. For other types see the `Hashcraft::MutatorRegistry` file.
151
151
 
152
152
  ### Internationalization Support
153
153
 
@@ -155,7 +155,7 @@ There is currently no first-class support for internationalization, but you can
155
155
 
156
156
  ### Transformers
157
157
 
158
- Transformers are optional but come into play when you need any additional/special processing of keys and values. By default, keys and values use the pass-thru transformer (Hashable::Transformers::PassThru) but can be explicitly passed any object that responds to `#transform(value, option)`.
158
+ Transformers are optional but come into play when you need any additional/special processing of keys and values. By default, keys and values use the pass-thru transformer, `Hashcraft::Transformers::PassThru`, but can be explicitly passed any object that responds to `#transform(value, option)`.
159
159
 
160
160
  #### Key Transformer Example
161
161
 
@@ -171,12 +171,35 @@ Say, for example, we wanted to transform all keys to camel case. We could creat
171
171
  end
172
172
  ````
173
173
 
174
- We can then use this when deriving hashes (using the above Grid example):
174
+ We can then use this when deriving hashes (building on the Grid example above):
175
175
 
176
176
  ````ruby
177
+ class Content < Hashcraft::Base
178
+ option :property
179
+ end
180
+
181
+ class Column < Hashcraft::Base
182
+ option :header
183
+
184
+ option :content, craft: Content,
185
+ mutator: :array,
186
+ key: :contents
187
+ end
188
+
189
+ class Grid < Hashcraft::Base
190
+ key_transformer CamelCase.new
191
+
192
+ option :api_url,
193
+ :name
194
+
195
+ option :column, craft: Column,
196
+ mutator: :array,
197
+ key: :columns
198
+ end
199
+
177
200
  config = Grid.new do
178
201
  api_url '/patients'
179
- end.to_h(key_transformer: CamelCase.new)
202
+ end.to_h
180
203
  ````
181
204
 
182
205
  The resulting `config` value will now be:
@@ -190,12 +213,23 @@ The resulting `config` value will now be:
190
213
  Note that this library ships with some basic transformers like the one mentioned above. If you want to use this then you can simply do this:
191
214
 
192
215
  ````ruby
216
+ class Grid < Hashcraft::Base
217
+ key_transformer :camel_case
218
+
219
+ option :api_url,
220
+ :name
221
+
222
+ option :column, craft: Column,
223
+ mutator: :array,
224
+ key: :columns
225
+ end
226
+
193
227
  config = Grid.new do
194
228
  api_url '/patients'
195
- end.to_h(key_transformer: :camel_case)
229
+ end.to_h
196
230
  ````
197
231
 
198
- See Hashcraft::TransformerRegistry for a full list of provided transformers.
232
+ See the `Hashcraft::TransformerRegistry` file for a full list of provided transformers.
199
233
 
200
234
  #### Value Transformer Example
201
235
 
@@ -213,10 +247,12 @@ class Localizer
213
247
  end
214
248
  ````
215
249
 
216
- Building on our Grid example, we could enhance the Column object as such:
250
+ Building on our Grid example, we could enhance the Column object:
217
251
 
218
252
  ````ruby
219
253
  class Column < Hashcraft::Base
254
+ value_transformer Localizer.new
255
+
220
256
  option :header, meta: { localize: true }
221
257
 
222
258
  option :content, craft: Content,
@@ -225,7 +261,7 @@ class Column < Hashcraft::Base
225
261
  end
226
262
  ````
227
263
 
228
- We can then use the new value transformer (Localizer) when deriving hashes (using the above Grid and updated Column example):
264
+ We can then use the new value transformer, `Localizer`, when deriving hashes (building on the above Grid and updated Column example):
229
265
 
230
266
  ````yaml
231
267
  en:
@@ -237,7 +273,7 @@ en:
237
273
  config = Grid.new do
238
274
  column header: :id
239
275
  column header: :first
240
- end.to_h(value_transformer: Localizer.new)
276
+ end.to_h
241
277
  ````
242
278
 
243
279
  Assuming our en.yml looks like the above example and our locale is set to:en then the resulting `config` value will now be:
@@ -10,13 +10,8 @@
10
10
  require 'forwardable'
11
11
  require 'singleton'
12
12
 
13
- # Monkey-patching core libraries
14
- require_relative 'hashcraft/core_ext/hash'
15
- Hash.include Hashcraft::CoreExt::Hash
16
-
17
13
  # General tooling
18
14
  require_relative 'hashcraft/generic'
19
15
 
16
+ # Main Entrypoint(s)
20
17
  require_relative 'hashcraft/base'
21
- require_relative 'hashcraft/mutator_registry'
22
- require_relative 'hashcraft/transformer_registry'
@@ -7,7 +7,6 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
- require_relative 'compiler'
11
10
  require_relative 'dsl'
12
11
 
13
12
  module Hashcraft
@@ -17,13 +16,15 @@ module Hashcraft
17
16
  extend Forwardable
18
17
 
19
18
  def_delegators :'self.class',
20
- :option?,
21
19
  :option_set,
22
- :find_option
20
+ :find_option,
21
+ :key_transformer_to_use,
22
+ :value_transformer_to_use
23
23
 
24
24
  def initialize(opts = {}, &block)
25
- @data = make_default_data
25
+ @data = {}
26
26
 
27
+ load_default_data
27
28
  load_opts(opts)
28
29
 
29
30
  return unless block_given?
@@ -35,36 +36,67 @@ module Hashcraft
35
36
  end
36
37
  end
37
38
 
38
- def to_h(key_transformer: nil, value_transformer: nil)
39
- Compiler.new(
40
- option_set,
41
- key_transformer: key_transformer,
42
- value_transformer: value_transformer
43
- ).evaluate!(data)
39
+ # Main compilation method. Once an object is hydrated, you can call this method to get the
40
+ # materialized hash.
41
+ def to_h
42
+ data.each_with_object({}) do |(key, value), memo|
43
+ method = value.is_a?(Array) ? :evaluate_values! : :evaluate_value!
44
+
45
+ send(method, memo, key, value)
46
+ end
44
47
  end
45
48
 
46
49
  private
47
50
 
48
51
  attr_reader :data
49
52
 
50
- def make_default_data
51
- option_set.values.each_with_object({}) { |o, memo| o.default!(memo) }
53
+ def load_default_data
54
+ option_set.each { |option| default!(option) }
52
55
  end
53
56
 
54
57
  def load_opts(opts)
55
58
  (opts || {}).each { |k, v| send(k, v) }
56
59
  end
57
60
 
58
- def respond_to_missing?(method_name, include_private = false)
59
- option?(method_name) || super
60
- end
61
+ def evaluate_values!(data, key, values)
62
+ data[key] ||= []
61
63
 
62
- def method_missing(method_name, *arguments, &block)
63
- if option?(method_name)
64
- find_option(method_name).value!(data, arguments.first, &block)
65
- else
66
- super
64
+ values.each do |value|
65
+ data[key] << (value.is_a?(Hashcraft::Base) ? value.to_h : value)
67
66
  end
67
+
68
+ self
69
+ end
70
+
71
+ def evaluate_value!(data, key, value)
72
+ data[key] = (value.is_a?(Hashcraft::Base) ? value.to_h : value)
73
+
74
+ self
75
+ end
76
+
77
+ def default!(option)
78
+ return self unless option.eager?
79
+
80
+ key = hash_key(option)
81
+ value = value_transformer_to_use.transform(option.default.dup, option)
82
+
83
+ data[key] = value
84
+
85
+ self
86
+ end
87
+
88
+ def value!(option, value, &block)
89
+ key = hash_key(option)
90
+ value = option.craft_value(value, &block)
91
+ value = value_transformer_to_use.transform(value, option)
92
+
93
+ option.value!(data, key, value)
94
+
95
+ self
96
+ end
97
+
98
+ def hash_key(option)
99
+ key_transformer_to_use.transform(option.hash_key, option)
68
100
  end
69
101
  end
70
102
  end
@@ -8,20 +8,54 @@
8
8
  #
9
9
 
10
10
  require_relative 'option'
11
+ require_relative 'transformer_registry'
11
12
 
12
13
  module Hashcraft
13
14
  # The class API used to define options for a craftable class. Each class stores its own
14
15
  # OptionSet instance along with materializing one for its
15
16
  # inheritance chain (child has precedence.)
16
17
  module Dsl
17
- def option?(name)
18
- option_set.exist?(name)
18
+ attr_reader :local_key_transformer,
19
+ :local_value_transformer
20
+
21
+ # DSL Method used to declare what the sub-class should use as a transformer for all keys.
22
+ # It will follow the typical inheritance chain and find the closest
23
+ # transformer to use (child-first).
24
+ def key_transformer(name)
25
+ tap { @local_key_transformer = TransformerRegistry.resolve(name) }
26
+ end
27
+
28
+ # DSL Method used to declare what the sub-class should use as a transformer for all values.
29
+ # It will follow the typical inheritance chain and find the closest
30
+ # transformer to use (child-first).
31
+ def value_transformer(name)
32
+ tap { @local_value_transformer = TransformerRegistry.resolve(name) }
33
+ end
34
+
35
+ def key_transformer_to_use # :nodoc:
36
+ return @key_transformer_to_use if @key_transformer_to_use
37
+
38
+ @closest_key_transformer =
39
+ ancestors.select { |a| a < Base }
40
+ .find(&:local_key_transformer)
41
+ &.local_key_transformer || Transformers::PassThru.instance
19
42
  end
20
43
 
21
- def find_option(name)
44
+ def value_transformer_to_use # :nodoc:
45
+ return @value_transformer_to_use if @value_transformer_to_use
46
+
47
+ @closest_value_transformer =
48
+ ancestors.select { |a| a < Base }
49
+ .find(&:local_value_transformer)
50
+ &.local_value_transformer || Transformers::PassThru.instance
51
+ end
52
+
53
+ def find_option(name) # :nodoc:
22
54
  option_set.find(name)
23
55
  end
24
56
 
57
+ # The main class-level DSL method consumed by sub-classes. This is the entry-point for the
58
+ # declaration of available options.
25
59
  def option(*args)
26
60
  opts = args.last.is_a?(Hash) ? args.pop : {}
27
61
 
@@ -29,12 +63,22 @@ module Hashcraft
29
63
  option = Option.new(key, opts)
30
64
 
31
65
  local_option_set.add(option)
66
+
67
+ method_name = option.name
68
+
69
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
70
+ def #{method_name}(opts = {}, &block)
71
+ option = find_option('#{method_name}')
72
+
73
+ value!(option, opts, &block)
74
+ end
75
+ RUBY
32
76
  end
33
77
 
34
78
  self
35
79
  end
36
80
 
37
- def option_set
81
+ def option_set # :nodoc:
38
82
  @option_set ||=
39
83
  ancestors
40
84
  .reverse
@@ -42,7 +86,7 @@ module Hashcraft
42
86
  .each_with_object(Generic::Dictionary.new) { |a, memo| memo.merge!(a.local_option_set) }
43
87
  end
44
88
 
45
- def local_option_set
89
+ def local_option_set # :nodoc:
46
90
  @local_option_set ||= Generic::Dictionary.new(key: :name)
47
91
  end
48
92
  end
@@ -8,7 +8,7 @@
8
8
  #
9
9
 
10
10
  module Hashcraft
11
- module Generic
11
+ module Generic # :nodoc: all
12
12
  # Dictionary structure defining how we want to organize objects. Basically a type-insensitive
13
13
  # hash where each key is the object's value for the specified key.
14
14
  # All keys are #to_s evaluated in order to achieve the type-insensitivity.
@@ -28,8 +28,10 @@ module Hashcraft
28
28
  freeze
29
29
  end
30
30
 
31
- def exist?(key)
32
- !find(key).nil?
31
+ def each(&block)
32
+ return enum_for(:each) unless block_given?
33
+
34
+ values.each(&block)
33
35
  end
34
36
 
35
37
  def find(key)
@@ -8,7 +8,7 @@
8
8
  #
9
9
 
10
10
  module Hashcraft
11
- module Generic
11
+ module Generic # :nodoc: all
12
12
  # A general data structure that can register and resolve objects by name.
13
13
  # It also will act as a pass-thru if a non-string or non-symbol is passed through.
14
14
  class Registry
@@ -46,11 +46,7 @@ module Hashcraft
46
46
  def resolve(value)
47
47
  return value unless lookup?(value)
48
48
 
49
- mutator = map[value.to_s]
50
-
51
- raise ArgumentError, "registration: #{value} not found" unless mutator
52
-
53
- mutator
49
+ map[value.to_s] || raise(ArgumentError, "registration: #{value} not found")
54
50
  end
55
51
 
56
52
  private
@@ -7,19 +7,25 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
+ require_relative 'mutators/always_false'
11
+ require_relative 'mutators/always_true'
10
12
  require_relative 'mutators/array'
13
+ require_relative 'mutators/flat_array'
11
14
  require_relative 'mutators/hash'
12
15
  require_relative 'mutators/property'
13
16
 
14
17
  module Hashcraft
15
18
  # Singleton that knows how to register and retrieve mutator instances.
16
- class MutatorRegistry < Generic::Registry
19
+ class MutatorRegistry < Generic::Registry # :nodoc:
17
20
  def initialize
18
21
  super(
22
+ '' => Mutators::Property.instance,
23
+ 'always_false' => Mutators::AlwaysFalse.instance,
24
+ 'always_true' => Mutators::AlwaysTrue.instance,
19
25
  'array' => Mutators::Array.instance,
26
+ 'flat_array' => Mutators::FlatArray.instance,
20
27
  'hash' => Mutators::Hash.instance,
21
- 'property' => Mutators::Property.instance,
22
- '' => Mutators::Property.instance
28
+ 'property' => Mutators::Property.instance
23
29
  )
24
30
  end
25
31
  end
@@ -8,13 +8,13 @@
8
8
  #
9
9
 
10
10
  module Hashcraft
11
- module CoreExt
12
- # Monkey-patches for the core Hash class. These will be manually mixed in separately.
13
- module Hash
14
- unless method_defined?(:symbolize_keys)
15
- def symbolize_keys
16
- map { |k, v| [k.to_sym, v] }.to_h
17
- end
11
+ module Mutators # :nodoc: all
12
+ # Set to false, no matter what.
13
+ class AlwaysFalse
14
+ include Singleton
15
+
16
+ def value!(data, key, _value)
17
+ tap { data[key] = false }
18
18
  end
19
19
  end
20
20
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Hashcraft
11
+ module Mutators # :nodoc: all
12
+ # Set to true, no matter what.
13
+ class AlwaysTrue
14
+ include Singleton
15
+
16
+ def value!(data, key, _value)
17
+ tap { data[key] = true }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -8,14 +8,15 @@
8
8
  #
9
9
 
10
10
  module Hashcraft
11
- module Mutators
12
- # When a hash's key is an arry then this mutator can be used to push a new value on the
11
+ module Mutators # :nodoc: all
12
+ # When a hash's key is an array then this mutator can be used to push a new value on the
13
13
  # respective array.
14
14
  class Array
15
15
  include Singleton
16
16
 
17
17
  def value!(data, key, value)
18
18
  data[key] ||= []
19
+
19
20
  data[key] << value
20
21
 
21
22
  self
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Hashcraft
11
+ module Mutators # :nodoc: all
12
+ # If the value is an array then concat, if it is not an array then push.
13
+ class FlatArray
14
+ include Singleton
15
+
16
+ def value!(data, key, value)
17
+ data[key] ||= []
18
+
19
+ # Prefixed Array with double colons to not get confused with our Array mutator class.
20
+ if value.is_a?(::Array)
21
+ data[key] += value
22
+ else
23
+ data[key] << value
24
+ end
25
+
26
+ self
27
+ end
28
+ end
29
+ end
30
+ end
@@ -8,7 +8,7 @@
8
8
  #
9
9
 
10
10
  module Hashcraft
11
- module Mutators
11
+ module Mutators # :nodoc: all
12
12
  # When a hash's key a Hash then this mutator can be used to merge a new value on the
13
13
  # respective hash.
14
14
  class Hash
@@ -8,16 +8,14 @@
8
8
  #
9
9
 
10
10
  module Hashcraft
11
- module Mutators
11
+ module Mutators # :nodoc: all
12
12
  # When a hash key can be simply assigned to (like a property) then this mutator can be used to
13
13
  # simply do the assignment.
14
14
  class Property
15
15
  include Singleton
16
16
 
17
17
  def value!(data, key, value)
18
- data[key] = value
19
-
20
- self
18
+ tap { data[key] = value }
21
19
  end
22
20
  end
23
21
  end
@@ -7,6 +7,8 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
+ require_relative 'mutator_registry'
11
+
10
12
  module Hashcraft
11
13
  # Defines a method and corresponding attribute for a craftable class.
12
14
  class Option
@@ -17,46 +19,47 @@ module Hashcraft
17
19
  :mutator,
18
20
  :name
19
21
 
20
- def initialize(name, opts = {})
22
+ alias eager? eager
23
+
24
+ def initialize(name, opts = {}) # :nodoc:
21
25
  raise ArgumentError, 'name is required' if name.to_s.empty?
22
26
 
23
- @craft = opts[:craft]
24
- @default = opts[:default]
25
- @eager = opts[:eager] || false
26
- @internal_meta = (opts[:meta] || {}).symbolize_keys
27
- @key = opts[:key].to_s
28
- @mutator = MutatorRegistry.resolve(opts[:mutator])
29
- @name = name.to_s
27
+ @craft = opts[:craft]
28
+ @default = opts[:default]
29
+ @eager = opts[:eager] || false
30
+ @internal_meta = symbolize_keys(opts[:meta] || {})
31
+ @key = opts[:key].to_s
32
+ @mutator = MutatorRegistry.resolve(opts[:mutator])
33
+ @name = name.to_s
30
34
 
31
35
  freeze
32
36
  end
33
37
 
38
+ def value!(data, key, value) # :nodoc:
39
+ mutator.value!(data, key, value)
40
+ end
41
+
42
+ # Options are sent into transformers as arguments. Leverage the meta key for an option
43
+ # to store any additional data that you may need in transformers. This method provides a
44
+ # quick message-based entry point into inspecting the meta key's value.
34
45
  def meta(key)
35
46
  internal_meta[key.to_s.to_sym]
36
47
  end
37
48
 
38
- def default!(data)
39
- return self unless eager
40
-
41
- data[name] = default
42
-
43
- self
49
+ def hash_key # :nodoc:
50
+ key.empty? ? name : key
44
51
  end
45
52
 
46
- def value!(data, value, &block)
47
- value = craft_value(value, &block)
48
-
49
- mutator.value!(data, name, value)
50
-
51
- self
53
+ def craft_value(value, &block) # :nodoc:
54
+ craft ? craft.new(value, &block) : value
52
55
  end
53
56
 
54
57
  private
55
58
 
56
59
  attr_reader :internal_meta
57
60
 
58
- def craft_value(value, &block)
59
- craft ? craft.new(value, &block) : value
61
+ def symbolize_keys(hash)
62
+ hash.map { |k, v| [k.to_sym, v] }.to_h
60
63
  end
61
64
  end
62
65
  end
@@ -13,13 +13,13 @@ require_relative 'transformers/pass_thru'
13
13
 
14
14
  module Hashcraft
15
15
  # Singleton that knows how to register and retrieve transformer instances.
16
- class TransformerRegistry < Generic::Registry
16
+ class TransformerRegistry < Generic::Registry # :nodoc:
17
17
  def initialize
18
18
  super(
19
+ '' => Transformers::PassThru.instance,
19
20
  'camel_case' => Transformers::CamelCase.instance,
20
21
  'pascal_case' => Transformers::PascalCase.instance,
21
- 'pass_thru' => Transformers::PassThru.instance,
22
- '' => Transformers::PassThru.instance
22
+ 'pass_thru' => Transformers::PassThru.instance
23
23
  )
24
24
  end
25
25
  end
@@ -8,7 +8,7 @@
8
8
  #
9
9
 
10
10
  module Hashcraft
11
- module Transformers
11
+ module Transformers # :nodoc: all
12
12
  # Transform snake-cased to camel-cased string. Example:
13
13
  # date_of_birth => dateOfBirth
14
14
  # DATE_OF_BIRTH => dateOfBirth
@@ -8,7 +8,7 @@
8
8
  #
9
9
 
10
10
  module Hashcraft
11
- module Transformers
11
+ module Transformers # :nodoc: all
12
12
  # Transform snake-cased to pascal-cased string. Example:
13
13
  # date_of_birth => DateOfBirth
14
14
  # DATE_OF_BIRTH => DateOfBirth
@@ -8,7 +8,7 @@
8
8
  #
9
9
 
10
10
  module Hashcraft
11
- module Transformers
11
+ module Transformers # :nodoc: all
12
12
  # Default transformer, simply returns the value passed in.
13
13
  class PassThru
14
14
  include Singleton
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module Hashcraft
11
- VERSION = '1.0.0-alpha.1'
11
+ VERSION = '1.0.0-alpha.6'
12
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hashcraft
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.alpha.1
4
+ version: 1.0.0.pre.alpha.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-07-01 00:00:00.000000000 Z
11
+ date: 2020-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: guard-rspec
@@ -132,14 +132,15 @@ files:
132
132
  - hashcraft.gemspec
133
133
  - lib/hashcraft.rb
134
134
  - lib/hashcraft/base.rb
135
- - lib/hashcraft/compiler.rb
136
- - lib/hashcraft/core_ext/hash.rb
137
135
  - lib/hashcraft/dsl.rb
138
136
  - lib/hashcraft/generic.rb
139
137
  - lib/hashcraft/generic/dictionary.rb
140
138
  - lib/hashcraft/generic/registry.rb
141
139
  - lib/hashcraft/mutator_registry.rb
140
+ - lib/hashcraft/mutators/always_false.rb
141
+ - lib/hashcraft/mutators/always_true.rb
142
142
  - lib/hashcraft/mutators/array.rb
143
+ - lib/hashcraft/mutators/flat_array.rb
143
144
  - lib/hashcraft/mutators/hash.rb
144
145
  - lib/hashcraft/mutators/property.rb
145
146
  - lib/hashcraft/option.rb
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #
4
- # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
- #
6
- # This source code is licensed under the MIT license found in the
7
- # LICENSE file in the root directory of this source tree.
8
- #
9
-
10
- module Hashcraft
11
- # This class understands how to traverse an option chain and output a hash.
12
- class Compiler
13
- attr_reader :key_transformer, :option_set, :value_transformer
14
-
15
- def initialize(option_set, key_transformer: nil, value_transformer: nil)
16
- raise ArgumentError, 'option_set is required' unless option_set
17
-
18
- @option_set = option_set
19
- @key_transformer = TransformerRegistry.resolve(key_transformer)
20
- @value_transformer = TransformerRegistry.resolve(value_transformer)
21
-
22
- freeze
23
- end
24
-
25
- def evaluate!(data)
26
- data.each_with_object({}) do |(key, value), memo|
27
- option = option_set.find(key)
28
-
29
- evaluate_single!(memo, option, value)
30
- end
31
- end
32
-
33
- private
34
-
35
- attr_reader :data
36
-
37
- def evaluate_single!(data, option, value)
38
- key = option.key.empty? ? option.name : option.key
39
- transformed_key = key_transformer.transform(key, option)
40
-
41
- method = value.is_a?(Array) ? :evaluate_values! : :evaluate_value!
42
-
43
- send(method, option, data, transformed_key, value)
44
-
45
- self
46
- end
47
-
48
- def evaluate_values!(option, data, key, values)
49
- data[key] ||= []
50
-
51
- values.each do |value|
52
- data[key] <<
53
- if value.is_a?(Hashcraft::Base)
54
- value.to_h(
55
- key_transformer: key_transformer,
56
- value_transformer: value_transformer
57
- )
58
- else
59
- value_transformer.transform(value, option)
60
- end
61
- end
62
-
63
- self
64
- end
65
-
66
- def evaluate_value!(option, data, key, value)
67
- data[key] =
68
- if value.is_a?(Hashcraft::Base)
69
- value.to_h(
70
- key_transformer: key_transformer,
71
- value_transformer: value_transformer
72
- )
73
- else
74
- value_transformer.transform(value, option)
75
- end
76
-
77
- self
78
- end
79
- end
80
- end