tdc 0.2.2 → 0.3.2

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: '047929ba6cb08c87ebab328779a9ad41c9860ad953ebe559f5d47bbc1d7ef53b'
4
- data.tar.gz: 83864de78f6680541319688a7a3e9a523dea3e87f5eeb6c2b234114c954842b3
3
+ metadata.gz: d440b515dda7b3c95c5ddabd279894b4bd6c93ac81a17c47fe0191d25fb72391
4
+ data.tar.gz: 6878b050a7fc779362fe8b7f3d95e1e0337742e060df42899827a2743290a174
5
5
  SHA512:
6
- metadata.gz: fd7913a43b6ca6c179b2b8b839db1f744a89bfe1cd563347290633e79bd46bb5ed58597da994ffd70e6245f68b8313490a1624769150561f80b359a93516255e
7
- data.tar.gz: 45d2f32e3030bd93bf1ddb3665bb1e6491849bcb3ebaf9b7bf32caddd4df3ec76f8289519a92abc83842ad86ea173d25d4d7aaa5709723011c566b2d4063748f
6
+ metadata.gz: 9a54735b2c05f8cbacee18ba4ea5721a0ebeb2be1c8dca6020384ff6088255333f1e2ff1ec708f9446036c851bb55c3b2ad23e528c7c5e79ca5199272bd1e625
7
+ data.tar.gz: 487e92c5064480bfe3f2a00a98b1e3e427d15ba3d53619b8e2f96275d7279a1f1b74cbf4c867060f466fbfdc018b9d8d15f85700e6f1b0dbca861c0eaf92fad0
@@ -17,6 +17,16 @@ Layout/MultilineMethodCallBraceLayout:
17
17
  Layout/SpaceAroundMethodCallOperator:
18
18
  Enabled: true
19
19
 
20
+ Lint/DeprecatedOpenSSLConstant:
21
+ Enabled: true
22
+
23
+ Lint/DuplicateElsifCondition:
24
+ Enabled: true
25
+
26
+ Lint/MixedRegexpCaptureTypes:
27
+ Enabled: true
28
+
29
+
20
30
  Lint/RaiseException:
21
31
  Enabled: true
22
32
 
@@ -59,15 +69,31 @@ RSpec/MultipleExpectations:
59
69
  RSpec/SubjectStub:
60
70
  Enabled: false
61
71
 
72
+ Style/AccessorGrouping:
73
+ Enabled: true
74
+
75
+ Style/ArrayCoercion:
76
+ Enabled: true
77
+
78
+ Style/BisectedAttrAccessor:
79
+ Enabled: true
80
+
62
81
  Style/BlockDelimiters:
63
82
  Enabled: true
64
83
  EnforcedStyle: line_count_based
65
84
  BracesRequiredMethods:
66
85
  - 'let'
86
+ - 'subject'
87
+
88
+ Style/CaseLikeIf:
89
+ Enabled: true
67
90
 
68
91
  Style/Documentation:
69
92
  Enabled: false
70
93
 
94
+ Style/EmptyMethod:
95
+ EnforcedStyle: expanded
96
+
71
97
  Style/ExponentialNotation:
72
98
  Enabled: true
73
99
 
@@ -75,9 +101,15 @@ Style/ExponentialNotation:
75
101
  Style/FrozenStringLiteralComment:
76
102
  Enabled: false
77
103
 
104
+ Style/HashAsLastArrayItem:
105
+ Enabled: true
106
+
78
107
  Style/HashEachMethods:
79
108
  Enabled: true
80
109
 
110
+ Style/HashLikeCase:
111
+ Enabled: true
112
+
81
113
  Style/HashTransformKeys:
82
114
  Enabled: true
83
115
 
@@ -89,6 +121,21 @@ Style/HashSyntax:
89
121
  Exclude:
90
122
  - 'Rakefile'
91
123
 
124
+ Style/RedundantAssignment:
125
+ Enabled: true
126
+
127
+ Style/RedundantFetchBlock:
128
+ Enabled: true
129
+
130
+ Style/RedundantFileExtensionInRequire:
131
+ Enabled: true
132
+
133
+ Style/RedundantRegexpCharacterClass:
134
+ Enabled: true
135
+
136
+ Style/RedundantRegexpEscape:
137
+ Enabled: true
138
+
92
139
  # No need to mention StandardError.
93
140
  Style/RescueStandardError:
94
141
  EnforcedStyle: implicit
@@ -6,6 +6,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.2] - 2020-07-27
10
+
11
+ - Return `self` from `DefinitionResolver#configure_current_catalog` to make it chainable
12
+
13
+ ## [0.3.1] - 2020-07-25
14
+
15
+ - Support DefinitionResolver instance registration
16
+
17
+ ## [0.3.0] - 2020-07-19
18
+
19
+ - Introduce the DefinitionResolver abstraction
20
+
21
+ ## [0.2.4] - 2020-07-19
22
+
23
+ - Improve Tdc::MissingOverrideError diagnostics
24
+
25
+ ## [0.2.3] - 2020-05-21
26
+
27
+ - Update the diagram in the README
28
+
9
29
  ## [0.2.2] - 2020-05-20
10
30
 
11
31
  - Adding specs
data/README.md CHANGED
@@ -4,7 +4,9 @@
4
4
 
5
5
  **Extension Points**
6
6
 
7
- Define your own test data generators by inheriting from ```StandardGenerator``` or ```Singular Generator```.
7
+ Define your own test data generators by inheriting from ```StandardGenerator``` or ```SingularGenerator```. Best practice is to define an ```ApplicationStandardGenerator``` and an ```ApplicationSingularGenerator``` and have all other generators inherit from them.
8
+
9
+ Define your own definition resolvers by inheriting from ```DefinitionResolver```. Best practice is to define an ```ApplicationDefinitionResolver``` and all other definition resolvers inherit from it.
8
10
 
9
11
  During generation the test data catalog will be represented by ```CatalogEntries``` that are populated by reading from ```YAML``` files with a ```DataDefinitionReader``` or provided directly by an ```InMemoryDataDefinition```.
10
12
 
Binary file
data/lib/tdc.rb CHANGED
@@ -1,26 +1,43 @@
1
1
  require "ostruct"
2
2
  require "yaml"
3
3
 
4
+ require "active_support"
4
5
  require "active_support/concern"
5
- require "active_support/core_ext/hash/indifferent_access"
6
+ require "active_support/core_ext"
6
7
 
8
+ require "tdc/version"
9
+
10
+ # Errors
11
+ require "tdc/fatal_error"
12
+ require "tdc/missing_override_error"
13
+
14
+ # Data Definition Hierarchy
7
15
  require "tdc/data_definition"
8
16
  require "tdc/data_definition_file_reader"
9
- require "tdc/fatal_error"
10
17
  require "tdc/in_memory_data_definition"
11
- require "tdc/missing_override_error"
12
- require "tdc/version"
13
18
  require "tdc/with_indifferent_access_decorator"
14
19
 
20
+ # Generators
15
21
  require "tdc/generators"
22
+
23
+ # Current Catalog
16
24
  require "tdc/generators/catalog_entries"
25
+
26
+ # Concerns
17
27
  require "tdc/generators/definition_resolvable"
18
28
  require "tdc/generators/definition_sourcable"
29
+
30
+ # Generator Hierarchy
19
31
  require "tdc/generators/generator_base"
20
- require "tdc/generators/instance_definition_configurable"
32
+ require "tdc/generators/configurable_generator"
21
33
  require "tdc/generators/singular_generator"
22
34
  require "tdc/generators/standard_generator"
23
35
 
36
+ # Definition Resolvers
37
+ require "tdc/definition_resolvers"
38
+ require "tdc/definition_resolvers/definition_resolver"
39
+ require "tdc/definition_resolvers/tag_resolver"
40
+
24
41
  #
25
42
  # A framework for building a Test Data Catalog
26
43
  #
@@ -4,7 +4,7 @@ module Tdc
4
4
  #
5
5
  class DataDefinition
6
6
  def read(*_path_elements)
7
- raise MissingOverrideError
7
+ raise MissingOverrideError, "Implement the 'read' method"
8
8
  end
9
9
 
10
10
  def with_indifferent_access
@@ -0,0 +1,7 @@
1
+ module Tdc
2
+ #
3
+ # Namespace to host definition resolvers.
4
+ #
5
+ module DefinitionResolvers
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ module Tdc
2
+ module DefinitionResolvers
3
+ #
4
+ # Base class for any definition resolver.
5
+ #
6
+ class DefinitionResolver
7
+ attr_reader :current_catalog
8
+
9
+ def configure_current_catalog(current_catalog)
10
+ @current_catalog = current_catalog
11
+
12
+ self
13
+ end
14
+
15
+ def resolve(_instance_definition)
16
+ raise Tdc::MissingOverrideError, "Implement the 'resolve' method"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,38 @@
1
+ module Tdc
2
+ module DefinitionResolvers
3
+ #
4
+ # Knows how to resolve the tag value for the specified instance_definition key by replacing it
5
+ # with an object sourced from the current catalog.
6
+ #
7
+ class TagResolver < Tdc::DefinitionResolvers::DefinitionResolver
8
+ attr_reader :key, :source
9
+
10
+ def initialize(key:, source:)
11
+ @key = key
12
+ @source = source
13
+ end
14
+
15
+ def resolve(instance_definition)
16
+ return unless instance_definition.key?(key)
17
+
18
+ # Lookup the source catalog entry in the current_catalog.
19
+ catalog_entry = instance_eval("current_catalog.#{source}", __FILE__, __LINE__)
20
+
21
+ # Before resolution the instance definition value is a tag.
22
+ tag = instance_definition[key]
23
+
24
+ # Use the tag to source an object from the current catalog.
25
+ sourced_object = catalog_entry.send(tag)
26
+
27
+ unless sourced_object
28
+ message = "Could not find a tag reference for '#{key}' in the catalog entries provided."
29
+
30
+ raise Tdc::FatalError, message
31
+ end
32
+
33
+ # Replace the tag value with the sourced object.
34
+ instance_definition[key] = sourced_object
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,6 +1,6 @@
1
1
  module Tdc
2
2
  #
3
- # Namespace to host generators
3
+ # Namespace to host generators.
4
4
  #
5
5
  module Generators
6
6
  end
@@ -5,27 +5,16 @@ module Tdc
5
5
  #
6
6
  # Shared implementation between the StandardGenerator and the SingularGenerator abstract classes.
7
7
  #
8
- module InstanceDefinitionConfigurable
9
- extend ActiveSupport::Concern
8
+ class ConfigurableGenerator < Tdc::Generators::GeneratorBase
9
+ include Tdc::Generators::DefinitionSourcable
10
10
 
11
- included do
12
- include Tdc::Generators::DefinitionSourcable
11
+ attr_reader :instance_definition
13
12
 
14
- attr_reader :instance_definition
15
-
16
- source_definition_from :instance_definition
17
- end
18
-
19
- private
20
-
21
- def configure_instance_definition(instance_definition)
22
- @instance_definition = instance_definition
23
- configure_definition_source(instance_definition)
24
- end
13
+ source_definition_from :instance_definition
25
14
 
26
15
  def run_resolvers_and_generate_instance
27
16
  run_atx_resolvers(instance_definition)
28
- run_tag_resolvers(instance_definition)
17
+ run_definition_resolvers(instance_definition)
29
18
 
30
19
  generate_instance
31
20
  end
@@ -34,16 +23,24 @@ module Tdc
34
23
  # Hook method: subclasses are expected to define how to generate a model instance.
35
24
  #
36
25
  def generate_instance
37
- raise Tdc::MissingOverrideError
26
+ raise Tdc::MissingOverrideError, "Implement the 'generate_instance' method"
38
27
  end
39
28
 
40
29
  #
41
30
  # Hook method: subclasses may include the DefinitionResolvable concern to override.
42
31
  #
43
- def run_tag_resolvers(_instance_definition)
32
+ def run_definition_resolvers(_instance_definition)
44
33
  # Do nothing
45
34
  end
46
35
 
36
+ private
37
+
38
+ def configure_instance_definition(instance_definition)
39
+ @instance_definition = instance_definition
40
+
41
+ configure_definition_source(instance_definition)
42
+ end
43
+
47
44
  def run_atx_resolvers(instance_definition)
48
45
  atx_definitions = instance_definition.select { |k, _v| /_atx$/ =~ k }
49
46
 
@@ -1,61 +1,48 @@
1
1
  module Tdc
2
2
  module Generators
3
3
  #
4
- # Knows how to resolve tag values in an instance definition. The tag value will be replaced
5
- # with a model instance from the current catalog.
4
+ # Knows how to resolve attribute values in an instance definition. The attribute value will be replaced
5
+ # by the result of invoking the registered resolver.
6
6
  #
7
- # The resolve_tag class macro is provided for generators to define tag resolution.
7
+ # The resolve_tag class macro is provided for generators to define tag resolution. The test data definition
8
+ # YAML file has attribute values than contain a catalog entry tag.
8
9
  #
9
10
  # Example:
10
11
  #
11
- # Suppose a particular instance definition contained { subcomponent: sc_snackers_minis }
12
- # then a generator could resolve the subcomponent by defining:
12
+ # Suppose a particular instance definition contained { subcomponent: sc_snackers_minis } then a generator
13
+ # could resolve the subcomponent tag to the current catalog by defining:
13
14
  #
14
15
  # resolve_tag key: :subcomponent, source: "item_master.items"
15
16
  #
17
+ # The register_definition_resolver class macro is provided for generators to define and register their own
18
+ # definition resolvers. The test data definition YAML file has attribute values than contain an arbitrary
19
+ # value that will typically be replaced by an instance of an object returned by the specified resolver.
20
+ #
16
21
  module DefinitionResolvable
17
22
  extend ActiveSupport::Concern
18
23
 
19
24
  included do
20
- class_attribute :_tag_resolvers, instance_writer: false
21
- self._tag_resolvers = []
25
+ class_attribute :_definition_resolvers, instance_writer: false
26
+
27
+ self._definition_resolvers = []
22
28
  end
23
29
 
24
30
  class_methods do
25
- def resolve_tag(key:, source:)
26
- _tag_resolvers << [key, source]
31
+ def register_definition_resolver(resolver_instance)
32
+ _definition_resolvers << resolver_instance
27
33
  end
28
- end
29
34
 
30
- def run_tag_resolvers(instance_definition)
31
- _tag_resolvers.each { |key, source| _resolve_tag_reference(instance_definition, key, source) }
35
+ def resolve_tag(key:, source:)
36
+ register_definition_resolver(Tdc::DefinitionResolvers::TagResolver.new(key: key, source: source))
37
+ end
32
38
  end
33
39
 
34
- private
40
+ def run_definition_resolvers(instance_definition)
41
+ _definition_resolvers.each do |definition_resolver|
42
+ definition_resolver.configure_current_catalog(current_catalog)
35
43
 
36
- #
37
- # Replace the tag value for the specified instance_definition key with an object sourced from the current catalog.
38
- #
39
- def _resolve_tag_reference(instance_definition, key, source)
40
- return unless instance_definition.key?(key)
41
-
42
- # Lookup the source catalog entry in the current_catalog.
43
- catalog_entry = instance_eval("current_catalog.#{source}", __FILE__, __LINE__)
44
-
45
- # Before resolution the instance definition value is a tag.
46
- tag = instance_definition[key]
47
-
48
- # Use the tag to source an object from the current catalog.
49
- sourced_object = catalog_entry.send(tag)
50
-
51
- unless sourced_object
52
- message = "Could not find a tag reference for '#{key}' in the catalog entries provided."
53
-
54
- raise Tdc::FatalError, message
44
+ definition_resolver.resolve(instance_definition)
55
45
  end
56
-
57
- # Replace the tag value with the sourced object.
58
- instance_definition[key] = sourced_object
59
46
  end
60
47
  end
61
48
  end
@@ -35,13 +35,13 @@ module Tdc
35
35
  def method_missing(method, *args)
36
36
  key = transform_method_to_definition_source_key(method)
37
37
 
38
- definition_source.key?(key) ? definition_source.fetch(key) : super
38
+ definition_source&.key?(key) ? definition_source.fetch(key) : super
39
39
  end
40
40
 
41
41
  def respond_to_missing?(method, include_all = false)
42
42
  key = transform_method_to_definition_source_key(method)
43
43
 
44
- definition_source.key?(key) ? true : super
44
+ definition_source&.key?(key) ? true : super
45
45
  end
46
46
 
47
47
  def transform_method_to_definition_source_key(method)
@@ -12,11 +12,11 @@ module Tdc
12
12
  end
13
13
 
14
14
  def generate
15
- raise Tdc::MissingOverrideError
15
+ raise Tdc::MissingOverrideError, "Implement the 'generate' method"
16
16
  end
17
17
 
18
18
  def instance_definitions
19
- raise Tdc::MissingOverrideError
19
+ raise Tdc::MissingOverrideError, "Implement the 'instance_definitions' method"
20
20
  end
21
21
  end
22
22
  end
@@ -5,15 +5,7 @@ module Tdc
5
5
  #
6
6
  # See also StandardGenerator.
7
7
  #
8
- class SingularGenerator < Tdc::Generators::GeneratorBase
9
- include Tdc::Generators::InstanceDefinitionConfigurable
10
-
11
- def initialize(data_definition, current_catalog)
12
- super
13
-
14
- @additional_definitions = {}
15
- end
16
-
8
+ class SingularGenerator < Tdc::Generators::ConfigurableGenerator
17
9
  def with_definition(additional_definitions)
18
10
  @additional_definitions = additional_definitions.stringify_keys.reject { |_, v| v == :missing_definition }
19
11
 
@@ -21,18 +13,22 @@ module Tdc
21
13
  end
22
14
 
23
15
  def generate
24
- configure_instance_definition(singular_instance_definition.merge(@additional_definitions))
16
+ configure_instance_definition(singular_instance_definition.merge(additional_definitions))
25
17
 
26
18
  run_resolvers_and_generate_instance
27
19
  end
28
20
 
29
21
  private
30
22
 
23
+ def additional_definitions
24
+ @additional_definitions || {}
25
+ end
26
+
31
27
  def singular_instance_definition
32
28
  all_instance_definitions = instance_definitions
33
29
 
34
30
  if all_instance_definitions.many?
35
- raise Tdc::FatalError, "For the moment we only generate a single model instance"
31
+ raise Tdc::FatalError, "A singular generator only generates a single model instance"
36
32
  end
37
33
 
38
34
  # Delete the tag so that the models do not need to filter it out.
@@ -5,9 +5,7 @@ module Tdc
5
5
  #
6
6
  # See also SingularGenerator.
7
7
  #
8
- class StandardGenerator < Tdc::Generators::GeneratorBase
9
- include Tdc::Generators::InstanceDefinitionConfigurable
10
-
8
+ class StandardGenerator < Tdc::Generators::ConfigurableGenerator
11
9
  def generate
12
10
  CatalogEntries.new.tap do |catalog_entries|
13
11
  instance_definitions.each do |instance_definition|
@@ -1,7 +1,3 @@
1
1
  module Tdc
2
- class MissingOverrideError < Tdc::FatalError
3
- def initialize
4
- super("Must be implemented")
5
- end
6
- end
2
+ MissingOverrideError = Class.new(Tdc::FatalError)
7
3
  end
@@ -1,3 +1,3 @@
1
1
  module Tdc
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.2"
3
3
  end
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
31
31
 
32
32
  spec.add_development_dependency "rake", ">= 12.1", "< 13.1"
33
33
  spec.add_development_dependency "rspec", ">= 3.9", "< 4.0"
34
- spec.add_development_dependency "rubocop", "~> 0.82"
35
- spec.add_development_dependency "rubocop-rspec", "~> 1.38"
34
+ spec.add_development_dependency "rubocop", "~> 0.88"
35
+ spec.add_development_dependency "rubocop-rspec", "~> 1.42"
36
36
  spec.add_development_dependency "simplecov", "~> 0.17"
37
37
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tdc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alistair McKinnell
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-20 00:00:00.000000000 Z
11
+ date: 2020-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -70,28 +70,28 @@ dependencies:
70
70
  requirements:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
- version: '0.82'
73
+ version: '0.88'
74
74
  type: :development
75
75
  prerelease: false
76
76
  version_requirements: !ruby/object:Gem::Requirement
77
77
  requirements:
78
78
  - - "~>"
79
79
  - !ruby/object:Gem::Version
80
- version: '0.82'
80
+ version: '0.88'
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: rubocop-rspec
83
83
  requirement: !ruby/object:Gem::Requirement
84
84
  requirements:
85
85
  - - "~>"
86
86
  - !ruby/object:Gem::Version
87
- version: '1.38'
87
+ version: '1.42'
88
88
  type: :development
89
89
  prerelease: false
90
90
  version_requirements: !ruby/object:Gem::Requirement
91
91
  requirements:
92
92
  - - "~>"
93
93
  - !ruby/object:Gem::Version
94
- version: '1.38'
94
+ version: '1.42'
95
95
  - !ruby/object:Gem::Dependency
96
96
  name: simplecov
97
97
  requirement: !ruby/object:Gem::Requirement
@@ -128,13 +128,16 @@ files:
128
128
  - lib/tdc.rb
129
129
  - lib/tdc/data_definition.rb
130
130
  - lib/tdc/data_definition_file_reader.rb
131
+ - lib/tdc/definition_resolvers.rb
132
+ - lib/tdc/definition_resolvers/definition_resolver.rb
133
+ - lib/tdc/definition_resolvers/tag_resolver.rb
131
134
  - lib/tdc/fatal_error.rb
132
135
  - lib/tdc/generators.rb
133
136
  - lib/tdc/generators/catalog_entries.rb
137
+ - lib/tdc/generators/configurable_generator.rb
134
138
  - lib/tdc/generators/definition_resolvable.rb
135
139
  - lib/tdc/generators/definition_sourcable.rb
136
140
  - lib/tdc/generators/generator_base.rb
137
- - lib/tdc/generators/instance_definition_configurable.rb
138
141
  - lib/tdc/generators/singular_generator.rb
139
142
  - lib/tdc/generators/standard_generator.rb
140
143
  - lib/tdc/in_memory_data_definition.rb
@@ -164,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
167
  - !ruby/object:Gem::Version
165
168
  version: '0'
166
169
  requirements: []
167
- rubygems_version: 3.1.3
170
+ rubygems_version: 3.1.4
168
171
  signing_key:
169
172
  specification_version: 4
170
173
  summary: A simple framework for creating a Test Data Catalog