mad_flatter 1.0.0.pre.alpha → 1.0.0.pre.beta

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
  SHA256:
3
- metadata.gz: 9421aaac109d1a01c3cdaefa7568f5e7430910b7c39453115d164d597a385ee4
4
- data.tar.gz: 4da615caefb3a66559da876648294d20e68d79ab2908e1178969e0a086c8ef33
3
+ metadata.gz: 996b96ff524cf36af3fc367f1de538beab06023345e7a45ba206b131d6106c08
4
+ data.tar.gz: 2d8672213da7902f712d4d40e14de3cc54305df6d19a53dfb0ed41a785fab335
5
5
  SHA512:
6
- metadata.gz: 3972e3988c894b65f521257fccc5ee9f2fc311fe44fbe029d893e7c3efd4f6a45f6db1f632005e62cf1b68a831e11acd1c0a429a5208c0755b8d1e1bb473465e
7
- data.tar.gz: 1c871897762dc09ac2c3d2b76d6a72dec702c37560f05f2951d653e653bbbf7718bf871fb1641107a7f9ce987be7cddd9ca0521ba7c320eceadb35c21b37495e
6
+ metadata.gz: b41f5116f99ee102ef8a46b95930832aa94c06255b4df886a85177fa474f73d48dbdf799cc6f20b2c29baa84e354400e6f758da28f590a45a4837a42ed234445
7
+ data.tar.gz: fa5ce245cb03083dacc0ff8c5ba2318d8b1c89c20c157332ddcd611860de3ba6d431cac9d828a9cf3aeae0f65855ad3d894c7a991c4fc0d7444b436f4da4eab9
data/.reek.yml ADDED
@@ -0,0 +1,18 @@
1
+ exclude_paths:
2
+ - vendor
3
+ - spec
4
+ detectors:
5
+ # TooManyInstanceVariables:
6
+ # exclude:
7
+ # - "Class1"
8
+ # - "Class2"
9
+ # private methods do not have to depend on instance state
10
+ # https://github.com/troessner/reek/blob/master/docs/Utility-Function.md
11
+ UtilityFunction:
12
+ public_methods_only: true
13
+ # Check for variable name that doesn't communicate its intent well enough
14
+ # https://github.com/troessner/reek/blob/master/docs/Uncommunicative-Variable-Name.md
15
+ UncommunicativeVariableName:
16
+ accept:
17
+ - /^_$/
18
+ - /^e$/
data/.rubocop.yml CHANGED
@@ -1,13 +1,193 @@
1
+ require:
2
+ - rubocop-performance
3
+ - rubocop-rspec
4
+
1
5
  AllCops:
2
- TargetRubyVersion: 2.3
6
+ TargetRubyVersion: 3.0.1
7
+ NewCops: enable
8
+ Exclude:
9
+ - '.git/**/*'
10
+ - '.idea/**/*'
11
+ - 'init/*'
12
+ - 'Rakefile'
13
+ - '*.gemspec'
14
+ - 'spec/**/*'
15
+ - 'vendor/**/*'
16
+ - 'scratch.rb'
17
+
18
+ # Align the elements of a hash literal if they span more than one line.
19
+ Layout/HashAlignment:
20
+ EnforcedLastArgumentHashStyle: always_ignore
21
+
22
+ # Alignment of parameters in multi-line method definition.
23
+ # The `with_fixed_indentation` style aligns the following lines with one
24
+ # level of indentation relative to the start of the line with the method
25
+ # definition.
26
+ #
27
+ # def my_method(a,
28
+ # b)
29
+ Layout/ParameterAlignment:
30
+ EnforcedStyle: with_fixed_indentation
3
31
 
4
- Style/StringLiterals:
32
+ # Alignment of parameters in multi-line method call.
33
+ # The `with_fixed_indentation` style aligns the following lines with one
34
+ # level of indentation relative to the start of the line with the method call.
35
+ #
36
+ # my_method(a,
37
+ # b)
38
+ Layout/ArgumentAlignment:
39
+ EnforcedStyle: with_fixed_indentation
40
+
41
+ # a = case n
42
+ # when 0
43
+ # x * 2
44
+ # else
45
+ # y / 3
46
+ # end
47
+ Layout/CaseIndentation:
48
+ EnforcedStyle: end
49
+
50
+ # Enforces a configured order of definitions within a class body
51
+ Layout/ClassStructure:
52
+ Enabled: true
53
+
54
+ # Align `end` with the matching keyword or starting expression except for
55
+ # assignments, where it should be aligned with the LHS.
56
+ Layout/EndAlignment:
57
+ EnforcedStyleAlignWith: variable
58
+ AutoCorrect: true
59
+
60
+ # The `consistent` style enforces that the first element in an array
61
+ # literal where the opening bracket and the first element are on
62
+ # seprate lines is indented the same as an array literal which is not
63
+ # defined inside a method call.
64
+ Layout/FirstArrayElementIndentation:
65
+ EnforcedStyle: consistent
66
+
67
+ # The `consistent` style enforces that the first key in a hash
68
+ # literal where the opening brace and the first key are on
69
+ # seprate lines is indented the same as a hash literal which is not
70
+ # defined inside a method call.
71
+ Layout/FirstHashElementIndentation:
72
+ EnforcedStyle: consistent
73
+
74
+ # Indent multi-line methods instead of aligning with periods
75
+ Layout/MultilineMethodCallIndentation:
76
+ EnforcedStyle: indented
77
+
78
+ # Allow `debug` in tasks for now
79
+ Lint/Debugger:
80
+ Exclude:
81
+ - 'RakeFile'
82
+
83
+ # A calculated magnitude based on number of assignments, branches, and
84
+ # conditions.
85
+ # NOTE: This is temporarily disabled until we can eliminate existing Rubocop
86
+ # complaints
87
+ Metrics/AbcSize:
88
+ Enabled: false
89
+
90
+ # Avoid long blocks with many lines.
91
+ Metrics/BlockLength:
92
+ Exclude:
93
+ - 'RakeFile'
94
+ - 'db/seeds.rb'
95
+ - 'spec/**/*.rb'
96
+
97
+ # Avoid classes longer than 100 lines of code.
98
+ # NOTE: This is temporarily disabled until we can eliminate existing Rubocop
99
+ # complaints
100
+ Metrics/ClassLength:
101
+ Max: 200
102
+ Exclude:
103
+ - 'spec/**/*.rb'
104
+
105
+ # A complexity metric that is strongly correlated to the number of test cases
106
+ # needed to validate a method.
107
+ Metrics/CyclomaticComplexity:
108
+ Max: 9
109
+
110
+ # Limit lines to 80 characters
111
+ Layout/LineLength:
112
+ Max: 120
113
+ Exclude:
114
+ - 'RakeFile'
115
+ - 'spec/**/*.rb'
116
+
117
+ # Avoid methods longer than 15 lines of code.
118
+ Metrics/MethodLength:
119
+ Max: 20
120
+ IgnoredMethods:
121
+ - swagger_path
122
+ - operation
123
+
124
+
125
+ # A complexity metric geared towards measuring complexity for a human reader.
126
+ Metrics/PerceivedComplexity:
127
+ Max: 10
128
+
129
+ # Naming/FileName:
130
+ # Exclude:
131
+ # - 'lib/file.rb'
132
+
133
+ # Allow `downcase == ` instead of forcing `casecmp`
134
+ Performance/Casecmp:
135
+ Enabled: false
136
+
137
+ # Require children definitions to be nested or compact in classes and modules
138
+ Style/ClassAndModuleChildren:
139
+ Enabled: false
140
+
141
+ # Document classes and non-namespace modules.
142
+ # (Disabled for now, may revisit later)
143
+ Style/Documentation:
144
+ Enabled: false
145
+
146
+ # Checks the formatting of empty method definitions.
147
+ Style/EmptyMethod:
148
+ EnforcedStyle: expanded
149
+
150
+ # Add the frozen_string_literal comment to the top of files to help transition
151
+ # to frozen string literals by default.
152
+ Style/FrozenStringLiteralComment:
153
+ EnforcedStyle: always
154
+
155
+ # Check for conditionals that can be replaced with guard clauses
156
+ Style/GuardClause:
157
+ Enabled: false
158
+
159
+ Style/MixinUsage:
160
+ Exclude:
161
+ - 'RakeFile'
162
+
163
+ # Avoid multi-line method signatures.
164
+ Style/MultilineMethodSignature:
165
+ Enabled: true
166
+
167
+ # Don't use option hashes when you can use keyword arguments.
168
+ Style/OptionHash:
169
+ Enabled: true
170
+
171
+ # Use return instead of return nil.
172
+ Style/ReturnNil:
173
+ Enabled: true
174
+
175
+ # Allow code like `return x, y` as it's occasionally handy.
176
+ Style/RedundantReturn:
177
+ AllowMultipleReturnValues: true
178
+
179
+ # Prefer symbols instead of strings as hash keys.
180
+ Style/StringHashKeys:
5
181
  Enabled: true
6
- EnforcedStyle: double_quotes
7
182
 
8
183
  Style/StringLiteralsInInterpolation:
9
184
  Enabled: true
10
185
  EnforcedStyle: double_quotes
11
186
 
12
- Layout/LineLength:
13
- Max: 120
187
+ # Checks if configured preferred methods are used over non-preferred.
188
+ Style/StringMethods:
189
+ Enabled: true
190
+
191
+ # Checks for use of parentheses around ternary conditions.
192
+ Style/TernaryParentheses:
193
+ EnforcedStyle: require_parentheses_when_complex
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.0.1
data/Gemfile CHANGED
@@ -1,12 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source "https://rubygems.org"
3
+ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in mad_flatter.gemspec
6
6
  gemspec
7
-
8
- gem "rake", "~> 13.0"
9
-
10
- gem "rspec", "~> 3.0"
11
-
12
- gem "rubocop", "~> 0.81.0"
data/Gemfile.lock ADDED
@@ -0,0 +1,100 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mad_flatter (1.0.0.pre.beta)
5
+ activesupport (~> 7.0, >= 7.0.3.1)
6
+ immutable_struct_ex (~> 0.2.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (7.0.3.1)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 1.6, < 2)
14
+ minitest (>= 5.1)
15
+ tzinfo (~> 2.0)
16
+ ast (2.4.2)
17
+ byebug (11.1.3)
18
+ coderay (1.1.3)
19
+ concurrent-ruby (1.1.10)
20
+ diff-lcs (1.5.0)
21
+ docile (1.4.0)
22
+ i18n (1.12.0)
23
+ concurrent-ruby (~> 1.0)
24
+ immutable_struct_ex (0.2.2)
25
+ json (2.6.2)
26
+ kwalify (0.7.2)
27
+ method_source (1.0.0)
28
+ minitest (5.16.2)
29
+ parallel (1.22.1)
30
+ parser (3.1.2.1)
31
+ ast (~> 2.4.1)
32
+ pry (0.14.1)
33
+ coderay (~> 1.1)
34
+ method_source (~> 1.0)
35
+ pry-byebug (3.10.1)
36
+ byebug (~> 11.0)
37
+ pry (>= 0.13, < 0.15)
38
+ rainbow (3.1.1)
39
+ reek (6.1.1)
40
+ kwalify (~> 0.7.0)
41
+ parser (~> 3.1.0)
42
+ rainbow (>= 2.0, < 4.0)
43
+ regexp_parser (2.5.0)
44
+ rexml (3.2.5)
45
+ rspec (3.11.0)
46
+ rspec-core (~> 3.11.0)
47
+ rspec-expectations (~> 3.11.0)
48
+ rspec-mocks (~> 3.11.0)
49
+ rspec-core (3.11.0)
50
+ rspec-support (~> 3.11.0)
51
+ rspec-expectations (3.11.0)
52
+ diff-lcs (>= 1.2.0, < 2.0)
53
+ rspec-support (~> 3.11.0)
54
+ rspec-mocks (3.11.1)
55
+ diff-lcs (>= 1.2.0, < 2.0)
56
+ rspec-support (~> 3.11.0)
57
+ rspec-support (3.11.0)
58
+ rubocop (1.35.0)
59
+ json (~> 2.3)
60
+ parallel (~> 1.10)
61
+ parser (>= 3.1.2.1)
62
+ rainbow (>= 2.2.2, < 4.0)
63
+ regexp_parser (>= 1.8, < 3.0)
64
+ rexml (>= 3.2.5, < 4.0)
65
+ rubocop-ast (>= 1.20.1, < 2.0)
66
+ ruby-progressbar (~> 1.7)
67
+ unicode-display_width (>= 1.4.0, < 3.0)
68
+ rubocop-ast (1.21.0)
69
+ parser (>= 3.1.1.0)
70
+ rubocop-performance (1.14.3)
71
+ rubocop (>= 1.7.0, < 2.0)
72
+ rubocop-ast (>= 0.4.0)
73
+ rubocop-rspec (2.12.1)
74
+ rubocop (~> 1.31)
75
+ ruby-progressbar (1.11.0)
76
+ simplecov (0.21.2)
77
+ docile (~> 1.1)
78
+ simplecov-html (~> 0.11)
79
+ simplecov_json_formatter (~> 0.1)
80
+ simplecov-html (0.12.3)
81
+ simplecov_json_formatter (0.1.4)
82
+ tzinfo (2.0.5)
83
+ concurrent-ruby (~> 1.0)
84
+ unicode-display_width (2.2.0)
85
+
86
+ PLATFORMS
87
+ x86_64-darwin-19
88
+
89
+ DEPENDENCIES
90
+ mad_flatter!
91
+ pry-byebug (~> 3.9)
92
+ reek (~> 6.1, >= 6.1.1)
93
+ rspec (>= 3.10)
94
+ rubocop (~> 1.31)
95
+ rubocop-performance (~> 1.14, >= 1.14.3)
96
+ rubocop-rspec (~> 2.12, >= 2.12.1)
97
+ simplecov (~> 0.21.2)
98
+
99
+ BUNDLED WITH
100
+ 2.3.20
data/README.md CHANGED
@@ -1,8 +1,139 @@
1
1
  # MadFlatter
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/mad_flatter`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ [![GitHub version](http://badge.fury.io/gh/gangelo%2Fmad_flatter.svg)](https://badge.fury.io/gh/gangelo%2Fmad_flatter)
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/mad_flatter.svg)](https://badge.fury.io/rb/mad_flatter)
6
+
7
+ [![](http://ruby-gem-downloads-badge.herokuapp.com/mad_flatter?type=total)](http://www.rubydoc.info/gems/mad_flatter/)
8
+ [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/mad_flatter/)
9
+
10
+ [![Report Issues](https://img.shields.io/badge/report-issues-red.svg)](https://github.com/gangelo/mad_flatter/issues)
11
+
12
+ [![License](http://img.shields.io/badge/license-MIT-yellowgreen.svg)](#license)
13
+
14
+ This is a work in process. No breaking changes are expected before v1.0.0.
15
+
16
+ TODO: Add specs.
17
+ TODO: Better documentation.
18
+
19
+ mad_flatter is a Ruby gem that takes a Ruby `Hash` and flattens the Hash keys to
20
+ create a new Hash with unique Hash keys; that is, embedded Hashes use their
21
+ respective keys as namespaces to create unique keys across the entire Hash.
22
+ For example:
23
+
24
+ ```ruby
25
+ user0 = {
26
+ name: 'john',
27
+ wife: { name: 'mary' },
28
+ children: {
29
+ child0: 'sam',
30
+ child1: 'martha'
31
+ }
32
+ }
33
+
34
+ result0 = MadFlatter::Service.new.execute(hash: user0)
35
+ #=>
36
+ {
37
+ :name=>"john",
38
+ :wife_name=>"mary",
39
+ :children_child0=>"sam",
40
+ :children_child1=>"martha"
41
+ }
42
+ ```
43
+
44
+ The `:namespace` option may be used to append to all Hash keys, to ensure that all Hash keys are unique across multiple Hashes with the same structure. For example:
45
+
46
+ ```ruby
47
+ # Continuing from the above example...
48
+ user1 = {
49
+ name: 'james',
50
+ wife: { name: 'molly' },
51
+ children: {
52
+ child0: 'steve',
53
+ child1: 'maybell'
54
+ }
55
+ }
56
+
57
+ options = { namespace: :ns1 }
58
+ result1 = MadFlatter::Service.new.execute(hash: user1, options: options)
59
+ #=>
60
+ {
61
+ :ns1_name=>"james",
62
+ :ns1_wife_name=>"molly",
63
+ :ns1_children_child0=>"steve",
64
+ :ns1_children_child1=>"maybell"
65
+ }
66
+
67
+ result0.merge(result1)
68
+ #=>
69
+ {
70
+ :name=>"john",
71
+ :wife_name=>"mary",
72
+ :children_child0=>"sam",
73
+ :children_child1=>"martha",
74
+ :ns1_name=>"james",
75
+ :ns1_wife_name=>"molly",
76
+ :ns1_children_child0=>"steve",
77
+ :ns1_children_child1=>"maybell"
78
+ }
79
+ ```
80
+
81
+ The metadata can optionally be returned by setting the `:metadata` option
82
+ to true. This option is `false` by default. For example:
83
+
84
+ ```ruby
85
+ best_cake = {
86
+ name: 'black forest',
87
+ options: {
88
+ cherries: false
89
+ }
90
+ }
91
+
92
+ options = { namespace: :best_cake, metadata: true }
93
+ result = MadFlatter::Service.new(options: options).execute(hash: best_cake)
94
+ #=>
95
+ {
96
+ :best_cake_name=>
97
+ {
98
+ :value=>"black forest",
99
+ :metadata=> {
100
+ :key=>:name,
101
+ :dig=>[]
102
+ }
103
+ },
104
+ :best_cake_options_cherries=> {
105
+ :value=>false,
106
+ :metadata=> {
107
+ :key=>:cherries,
108
+ :dig=>[:options]
109
+ }
110
+ }
111
+ }
112
+
113
+ result.each_pair do |key, value|
114
+ original_key = value[:metadata][:key]
115
+ original_value = best_cake.dig(*value[:metadata][:dig], original_key)
116
+ puts 'Original Hash key/value:'
117
+ puts "\t#{original_key} => \"#{original_value}\""
118
+ puts 'New Hash key/value:'
119
+ puts "\t#{key} => \"#{value[:value]}\""
120
+ puts
121
+ end
122
+ ```
123
+ Prints:
124
+
125
+ ```
126
+ Original Hash key/value:
127
+ name => "black forest"
128
+ New Hash key/value:
129
+ best_cake_name => "black forest"
130
+
131
+ Original Hash key/value:
132
+ cherries => "false"
133
+ New Hash key/value:
134
+ best_cake_options_cherries => "false"
135
+ ```
4
136
 
5
- TODO: Delete this and the text above, and describe your gem
6
137
 
7
138
  ## Installation
8
139
 
@@ -20,10 +151,6 @@ Or install it yourself as:
20
151
 
21
152
  $ gem install mad_flatter
22
153
 
23
- ## Usage
24
-
25
- TODO: Write usage instructions here
26
-
27
154
  ## Development
28
155
 
29
156
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/bin/console CHANGED
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "bundler/setup"
5
- require "mad_flatter"
4
+ require 'bundler/setup'
5
+ require 'mad_flatter'
6
6
 
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
9
9
 
10
10
  # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
12
- # Pry.start
11
+ require 'pry'
12
+ Pry.start
13
13
 
14
- require "irb"
15
- IRB.start(__FILE__)
14
+ # require "irb"
15
+ # IRB.start(__FILE__)
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MadFlatter
4
+ # Flattens the provided Hash and assigns the results to the #hash_info
5
+ # attribute. If a namespace is provided, the namespace is prepended to
6
+ # the Hash key name.
7
+ module HashInformable
8
+ def load_hash_info(hash:, namespace: nil, dig: [], hash_info: {})
9
+ hash.each do |key, value|
10
+ if value.is_a? Hash
11
+ load_hash_info(hash: value,
12
+ namespace: namespace,
13
+ dig: dig << key,
14
+ hash_info: hash_info)
15
+ dig.pop
16
+ else
17
+ assign_hash_info(hash_info: hash_info,
18
+ key: key,
19
+ value: value,
20
+ namespace: namespace,
21
+ dig: dig)
22
+ end
23
+
24
+ next
25
+ end
26
+
27
+ hash_info
28
+ end
29
+
30
+ private
31
+
32
+ def assign_hash_info(hash_info:, key:, value:, namespace:, dig:)
33
+ hash_key = [namespace, *dig, key].compact.join('_').to_sym
34
+
35
+ hash_info[hash_key] = {
36
+ value: value,
37
+ metadata: {
38
+ key: key,
39
+ dig: dig.dup
40
+ }
41
+ }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'hash_informable'
4
+
5
+ module MadFlatter
6
+ # Provides methods to load and return information about a given hash.
7
+ module HashLoadable
8
+ include HashInformable
9
+
10
+ private
11
+
12
+ def load_hash(hash, options)
13
+ raise ArgumentError, "Argument hash is not a Hash (#{hash.class})" unless hash.is_a? Hash
14
+
15
+ return {} if hash.blank?
16
+
17
+ hash_info = load_hash_info(hash: hash, namespace: options.namespace)
18
+ return hash_info if options.metadata?
19
+
20
+ strip_metadata(hash_info)
21
+ end
22
+
23
+ def strip_metadata(hash)
24
+ hash.transform_values do |metadata|
25
+ metadata[:value]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MadFlatter
4
+ # Defines methods to retrieve model hash values dynamically.
5
+ module HashRetrievable
6
+ module_function
7
+
8
+ # Returns the value of the hash using fully quaified hash names.
9
+ def get_hash_value(hash:, hash_info:)
10
+ hash.dig(*[hash_info[:dig], hash_info[:field_name]].flatten.compact)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MadFlatter
4
+ # Defines the metadata option hash key and acceptable hash key values.
5
+ module MetadataOptionable
6
+ # The option hash key for this option.
7
+ OPTION_METADATA = :metadata
8
+ # The valid option values for this option key.
9
+ OPTION_METADATA_INCLUDE = true
10
+ OPTION_METADATA_EXCLUDE = false
11
+ # The default value for this option.
12
+ OPTION_METADATA_DEFAULT = OPTION_METADATA_EXCLUDE
13
+ # The valid option key values for this option.
14
+ OPTION_METADATA_VALUES = [OPTION_METADATA_INCLUDE, OPTION_METADATA_EXCLUDE].freeze
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MadFlatter
4
+ # Defines the namespace option hash key
5
+ module NamespaceOptionable
6
+ # The option hash key for this option.
7
+ OPTION_NAMESPACE = :namespace
8
+ # The default value for this option - no namespace.
9
+ OPTION_NAMESPACE_DEFAULT = nil
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'immutable_struct_ex'
4
+ require_relative 'options'
5
+ require_relative 'options_validatable'
6
+
7
+ module MadFlatter
8
+ # Defines methods and attributes to manage options.
9
+ module Optionable
10
+ include OptionsValidatable
11
+
12
+ def options
13
+ @options || Options.default
14
+ end
15
+
16
+ private
17
+
18
+ def options=(value)
19
+ options_hash = value.to_h
20
+
21
+ validate_options! options: options_hash
22
+
23
+ @options = Options.new(**options_hash)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'immutable_struct_ex'
4
+ require_relative 'options_defaultable'
5
+ require_relative 'options_validatable'
6
+
7
+ module MadFlatter
8
+ # Defines methods to create options.
9
+ module Options
10
+ extend MadFlatter::OptionsDefaultable
11
+ extend MadFlatter::OptionsValidatable
12
+
13
+ class << self
14
+ def new(**options)
15
+ immutable_struct_ex = ImmutableStructEx.new(**options) do
16
+ def namespace?
17
+ namespace || false
18
+ end
19
+
20
+ def metadata?
21
+ metadata || false
22
+ end
23
+ end
24
+ validate_options! options: immutable_struct_ex.to_h
25
+ immutable_struct_ex
26
+ end
27
+
28
+ def with_defaults(options, defaults: DEFAULT_OPTIONS)
29
+ new(**defaults.to_h.merge(options.to_h))
30
+ end
31
+
32
+ def default
33
+ with_defaults({})
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'metadata_optionable'
4
+ require_relative 'namespace_optionable'
5
+
6
+ module MadFlatter
7
+ # Defines default options and their optionn values.
8
+ module OptionsDefaultable
9
+ include MadFlatter::MetadataOptionable
10
+ include MadFlatter::NamespaceOptionable
11
+
12
+ DEFAULT_OPTIONS = {
13
+ OPTION_NAMESPACE => OPTION_NAMESPACE_DEFAULT,
14
+ OPTION_METADATA => OPTION_METADATA_DEFAULT
15
+ }.freeze
16
+ end
17
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'metadata_optionable'
4
+ require_relative 'namespace_optionable'
5
+
6
+ module MadFlatter
7
+ # Methods to validate options.
8
+ module OptionsValidatable
9
+ include MadFlatter::MetadataOptionable
10
+ include MadFlatter::NamespaceOptionable
11
+
12
+ OPTIONS = [OPTION_METADATA, OPTION_NAMESPACE].freeze
13
+
14
+ def validate_options!(options:)
15
+ raise ArgumentError, 'options is not a Hash' unless options.is_a? Hash
16
+
17
+ validate_options_present! options: options
18
+
19
+ validate_option_keys! options: options
20
+ validate_option_metadata! metadata: options[:metadata]
21
+ validate_option_namespace! namespace: options[:namespace]
22
+ end
23
+
24
+ def validate_options_present!(options:)
25
+ raise ArgumentError, 'options is blank?' if options.blank?
26
+ end
27
+
28
+ def validate_option_keys!(options:)
29
+ invalid_options = options.except(*OPTIONS)&.keys
30
+
31
+ return if invalid_options.blank?
32
+
33
+ raise ArgumentError, 'One or more option keys were unrecognized. ' \
34
+ "#{OPTIONS} was expected but '#{invalid_options} was received."
35
+ end
36
+
37
+ def validate_option_metadata!(metadata:)
38
+ return if [TrueClass, FalseClass].include? metadata.class
39
+
40
+ raise ArgumentError, "option :#{OPTION_METADATA} value is invalid. " \
41
+ 'A TrueClass/FalseClass was expected ' \
42
+ "with the acceptable values #{OPTION_METADATA_VALUES} " \
43
+ "but '#{metadata}' (#{metadata.class}) was received."
44
+ end
45
+
46
+ def validate_option_namespace!(namespace:)
47
+ # :namespace is optional.
48
+ return if namespace.blank? || namespace.is_a?(Symbol)
49
+
50
+ raise ArgumentError, "option :#{OPTION_NAMESPACE} value is invalid. " \
51
+ 'A Symbol was expected ' \
52
+ "with the acceptable values #{OPTION_METADATA_VALUES} " \
53
+ "but '#{metadata}' (#{metadata.class}) was received."
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'hash_loadable'
4
+ require_relative 'optionable'
5
+
6
+ module MadFlatter
7
+ # This class provides functionality to load and flatten a Hash.
8
+ # Default options passed to the constructor may be overridden with
9
+ # options passed to the #execute method.
10
+ class Service
11
+ include HashLoadable
12
+ include Optionable
13
+
14
+ def initialize(options: nil)
15
+ # Accept whatever options are sent, but make sure
16
+ # we have defaults set up. #with_defaults
17
+ # will merge options into OptionsDefaultable::DEFAULT_OPTIONS
18
+ # so we have defaults for any options not passed.
19
+ self.options = Options.with_defaults options
20
+ end
21
+
22
+ def execute(hash:, options: nil)
23
+ # Merge options received into the default options passed through
24
+ # the constructor. Options received here, will override any options
25
+ # passed to the constructor, allowing us to retain defaut options
26
+ # while loading, and also provide option overrides as needed.
27
+ options = Options.with_defaults(options, defaults: self.options)
28
+
29
+ load_hash(hash, options)
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MadFlatter
4
- VERSION = "1.0.0-alpha"
4
+ VERSION = '1.0.0-beta'
5
5
  end
data/lib/mad_flatter.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "mad_flatter/version"
3
+ require 'active_support'
4
+ require_relative 'mad_flatter/version'
4
5
 
5
- module MadFlatter
6
- class Error < StandardError; end
7
- # Your code goes here...
6
+ Dir[File.join('.', 'lib/mad_flatter/**/*.rb')].each do |f|
7
+ require f
8
8
  end
metadata CHANGED
@@ -1,15 +1,165 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mad_flatter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.alpha
4
+ version: 1.0.0.pre.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - gangelo
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-15 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-08-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 7.0.3.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '7.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 7.0.3.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: immutable_struct_ex
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.2.0
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 0.2.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: pry-byebug
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.9'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.9'
61
+ - !ruby/object:Gem::Dependency
62
+ name: reek
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '6.1'
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: 6.1.1
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '6.1'
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: 6.1.1
81
+ - !ruby/object:Gem::Dependency
82
+ name: rspec
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '3.10'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '3.10'
95
+ - !ruby/object:Gem::Dependency
96
+ name: rubocop
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '1.31'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '1.31'
109
+ - !ruby/object:Gem::Dependency
110
+ name: rubocop-performance
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '1.14'
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: 1.14.3
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '1.14'
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: 1.14.3
129
+ - !ruby/object:Gem::Dependency
130
+ name: rubocop-rspec
131
+ requirement: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - "~>"
134
+ - !ruby/object:Gem::Version
135
+ version: '2.12'
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 2.12.1
139
+ type: :development
140
+ prerelease: false
141
+ version_requirements: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '2.12'
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: 2.12.1
149
+ - !ruby/object:Gem::Dependency
150
+ name: simplecov
151
+ requirement: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - "~>"
154
+ - !ruby/object:Gem::Version
155
+ version: 0.21.2
156
+ type: :development
157
+ prerelease: false
158
+ version_requirements: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - "~>"
161
+ - !ruby/object:Gem::Version
162
+ version: 0.21.2
13
163
  description: mad_flatter gem
14
164
  email:
15
165
  - web.gma@gmail.com
@@ -17,17 +167,30 @@ executables: []
17
167
  extensions: []
18
168
  extra_rdoc_files: []
19
169
  files:
170
+ - ".reek.yml"
20
171
  - ".rspec"
21
172
  - ".rubocop.yml"
173
+ - ".ruby-version"
22
174
  - CHANGELOG.md
23
175
  - CODE_OF_CONDUCT.md
24
176
  - Gemfile
177
+ - Gemfile.lock
25
178
  - LICENSE.txt
26
179
  - README.md
27
180
  - Rakefile
28
181
  - bin/console
29
182
  - bin/setup
30
183
  - lib/mad_flatter.rb
184
+ - lib/mad_flatter/hash_informable.rb
185
+ - lib/mad_flatter/hash_loadable.rb
186
+ - lib/mad_flatter/hash_retrievable.rb
187
+ - lib/mad_flatter/metadata_optionable.rb
188
+ - lib/mad_flatter/namespace_optionable.rb
189
+ - lib/mad_flatter/optionable.rb
190
+ - lib/mad_flatter/options.rb
191
+ - lib/mad_flatter/options_defaultable.rb
192
+ - lib/mad_flatter/options_validatable.rb
193
+ - lib/mad_flatter/service.rb
31
194
  - lib/mad_flatter/version.rb
32
195
  - sig/mad_flatter.rbs
33
196
  homepage: https://github.com/gangelo/mad_flatter
@@ -37,7 +200,7 @@ metadata:
37
200
  homepage_uri: https://github.com/gangelo/mad_flatter
38
201
  source_code_uri: https://github.com/gangelo/mad_flatter
39
202
  changelog_uri: https://github.com/gangelo/mad_flatter/blob/main/CHANGELOG.md
40
- post_install_message:
203
+ post_install_message:
41
204
  rdoc_options: []
42
205
  require_paths:
43
206
  - lib
@@ -52,8 +215,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
52
215
  - !ruby/object:Gem::Version
53
216
  version: 1.3.1
54
217
  requirements: []
55
- rubygems_version: 3.2.33
56
- signing_key:
218
+ rubygems_version: 3.2.15
219
+ signing_key:
57
220
  specification_version: 4
58
221
  summary: mad_flatter gem
59
222
  test_files: []