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

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: 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: []