tdc 0.2.2 → 0.3.2

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: '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