tdc 0.2.0 → 0.3.0

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: 9c04de93f4bf48d68994ce4b8adab06f21ebd2f44e3d47ce6f221400cdc8495d
4
- data.tar.gz: 93a7c7a9d9dc4ea4480cc464cf6dc7c6526b6e941a68d74de956572e3fe71864
3
+ metadata.gz: 6d7775cd9909b7d1aef1f59def823777cc24d6bbfc50ddfd41eda202f5f5f387
4
+ data.tar.gz: 11b7ddadec9d97e1953f34efdee8b66d6f0cb08213dd8d9a9e9d4ae8372687fa
5
5
  SHA512:
6
- metadata.gz: 4986b573ecf8e32558cbfafddba2218a21896f7b01c6197b42bdab1b117cdee729dd3f0cc58fb8907e577223dad3fcd42890a8fedc937e1a9f4280a3be2be224
7
- data.tar.gz: 25aad449a81724ff044343015835148683c540ba3080d298841152bca2b5ac79d29557f1b2de17d7e986d1556629c20a542e4360a7ece7c3c6998c3fc5971402
6
+ metadata.gz: 1f396da321ee096251062cd35ff6add1d19292591dc8fa019509fe432f2fd7faea74844ee4583fbb30bc03e9f8106fbeabdb403732ec5098d70c40b69e2c216c
7
+ data.tar.gz: 69cfdaa1a302ae2d458f6775db22134953db4f6f584ba9af36970f4865d308de9a44d9c5c6ec10e7db0a4ec5c05d340254a4458dfc843d6676225459e2542660
@@ -0,0 +1,16 @@
1
+ root = true
2
+
3
+ [*]
4
+
5
+ # Change these settings to your own preference
6
+ indent_style = space
7
+ indent_size = 2
8
+
9
+ # We recommend you to keep these unchanged
10
+ end_of_line = lf
11
+ charset = utf-8
12
+ trim_trailing_whitespace = true
13
+ insert_final_newline = true
14
+
15
+ [*.md]
16
+ trim_trailing_whitespace = false
data/.rspec CHANGED
@@ -1,3 +1,3 @@
1
1
  --format documentation
2
2
  --color
3
- --require spec_helper
3
+ --require tdc_spec_helper
@@ -64,10 +64,14 @@ Style/BlockDelimiters:
64
64
  EnforcedStyle: line_count_based
65
65
  BracesRequiredMethods:
66
66
  - 'let'
67
+ - 'subject'
67
68
 
68
69
  Style/Documentation:
69
70
  Enabled: false
70
71
 
72
+ Style/EmptyMethod:
73
+ EnforcedStyle: expanded
74
+
71
75
  Style/ExponentialNotation:
72
76
  Enabled: true
73
77
 
@@ -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.0] - 2020-07-19
10
+
11
+ - Introduce the DefinitionResolver abstraction
12
+
13
+ ## [0.2.4] - 2020-07-19
14
+
15
+ - Improve Tdc::MissingOverrideError diagnostics
16
+
17
+ ## [0.2.3] - 2020-05-21
18
+
19
+ - Update the diagram in the README
20
+
21
+ ## [0.2.2] - 2020-05-20
22
+
23
+ - Adding specs
24
+
25
+ ## [0.2.1] - 2020-05-19
26
+
27
+ - Adding specs
28
+
9
29
  ## [0.2.0] - 2020-05-19
10
30
 
11
31
  #### Breaking Changes
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,24 +1,43 @@
1
1
  require "ostruct"
2
+ require "yaml"
2
3
 
4
+ require "active_support"
3
5
  require "active_support/concern"
4
- require "active_support/core_ext/hash/indifferent_access"
6
+ require "active_support/core_ext"
5
7
 
8
+ require "tdc/version"
9
+
10
+ # Errors
11
+ require "tdc/fatal_error"
12
+ require "tdc/missing_override_error"
13
+
14
+ # Data Definition Hierarchy
6
15
  require "tdc/data_definition"
7
16
  require "tdc/data_definition_file_reader"
8
- require "tdc/fatal_error"
9
17
  require "tdc/in_memory_data_definition"
10
- require "tdc/version"
11
18
  require "tdc/with_indifferent_access_decorator"
12
19
 
20
+ # Generators
13
21
  require "tdc/generators"
22
+
23
+ # Current Catalog
14
24
  require "tdc/generators/catalog_entries"
25
+
26
+ # Concerns
15
27
  require "tdc/generators/definition_resolvable"
16
28
  require "tdc/generators/definition_sourcable"
29
+
30
+ # Generator Hierarchy
17
31
  require "tdc/generators/generator_base"
18
- require "tdc/generators/instance_definition_configurable"
32
+ require "tdc/generators/configurable_generator"
19
33
  require "tdc/generators/singular_generator"
20
34
  require "tdc/generators/standard_generator"
21
35
 
36
+ # Definition Resolvers
37
+ require "tdc/definition_resolvers"
38
+ require "tdc/definition_resolvers/definition_resolver"
39
+ require "tdc/definition_resolvers/tag_resolver"
40
+
22
41
  #
23
42
  # A framework for building a Test Data Catalog
24
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,18 @@
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
+ end
12
+
13
+ def resolve(_instance_definition)
14
+ raise Tdc::MissingOverrideError, "Implement the 'resolve' method"
15
+ end
16
+ end
17
+ end
18
+ 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,59 @@
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 specified 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 resolve_definition class macro is provided for generators to define definition resolution. The test data
18
+ # definition YAML file has attribute values than contain an arbitrary value that will typically be replaced by
19
+ # an instance of an object returned by the specified resolver.
20
+ #
21
+ # Example:
22
+ #
23
+ # Suppose a particular instance definition contained { pallet_number: P0001 } then a generator could resolve
24
+ # the pallet_number to a pallet instance by defining:
25
+ #
26
+ # resolve_definition :pallet_number, to: :pallet_id, resolver: "TestDataCatalog::Resolvers::PalletNumberResolver"
27
+ #
28
+ # The PalletNumberResolver class inherits from Tdc::DefinitionResolvers::DefinitionResolver.
29
+ #
16
30
  module DefinitionResolvable
17
31
  extend ActiveSupport::Concern
18
32
 
19
33
  included do
20
- class_attribute :_tag_resolvers, instance_writer: false
21
- self._tag_resolvers = []
34
+ class_attribute :_definition_resolvers, instance_writer: false
35
+
36
+ self._definition_resolvers = []
22
37
  end
23
38
 
24
39
  class_methods do
25
- def resolve_tag(key:, source:)
26
- _tag_resolvers << [key, source]
40
+ def resolve_definition(key:, to: nil, resolver:)
41
+ resolver_instance = resolver.constantize.new(key: key, to: to || key)
42
+
43
+ _definition_resolvers << resolver_instance
27
44
  end
28
- end
29
45
 
30
- def run_tag_resolvers(instance_definition)
31
- _tag_resolvers.each { |key, source| _resolve_tag_reference(instance_definition, key, source) }
46
+ def resolve_tag(key:, source:)
47
+ _definition_resolvers << Tdc::DefinitionResolvers::TagResolver.new(key: key, source: source)
48
+ end
32
49
  end
33
50
 
34
- private
35
-
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__)
51
+ def run_definition_resolvers(instance_definition)
52
+ _definition_resolvers.each do |definition_resolver|
53
+ definition_resolver.configure_current_catalog(current_catalog)
44
54
 
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
55
+ definition_resolver.resolve(instance_definition)
55
56
  end
56
-
57
- # Replace the tag value with the sourced object.
58
- instance_definition[key] = sourced_object
59
57
  end
60
58
  end
61
59
  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.0"
2
+ VERSION = "0.3.0"
3
3
  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.0
4
+ version: 0.3.0
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-19 00:00:00.000000000 Z
11
+ date: 2020-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -113,6 +113,7 @@ executables: []
113
113
  extensions: []
114
114
  extra_rdoc_files: []
115
115
  files:
116
+ - ".editorconfig"
116
117
  - ".gitignore"
117
118
  - ".rspec"
118
119
  - ".rubocop.yml"
@@ -127,13 +128,16 @@ files:
127
128
  - lib/tdc.rb
128
129
  - lib/tdc/data_definition.rb
129
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
130
134
  - lib/tdc/fatal_error.rb
131
135
  - lib/tdc/generators.rb
132
136
  - lib/tdc/generators/catalog_entries.rb
137
+ - lib/tdc/generators/configurable_generator.rb
133
138
  - lib/tdc/generators/definition_resolvable.rb
134
139
  - lib/tdc/generators/definition_sourcable.rb
135
140
  - lib/tdc/generators/generator_base.rb
136
- - lib/tdc/generators/instance_definition_configurable.rb
137
141
  - lib/tdc/generators/singular_generator.rb
138
142
  - lib/tdc/generators/standard_generator.rb
139
143
  - lib/tdc/in_memory_data_definition.rb
@@ -163,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
163
167
  - !ruby/object:Gem::Version
164
168
  version: '0'
165
169
  requirements: []
166
- rubygems_version: 3.1.3
170
+ rubygems_version: 3.1.4
167
171
  signing_key:
168
172
  specification_version: 4
169
173
  summary: A simple framework for creating a Test Data Catalog