tdc 0.1.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 +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +109 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +19 -0
- data/Gemfile +7 -0
- data/README.md +2 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/tdc.rb +32 -0
- data/lib/tdc/decorator_error.rb +3 -0
- data/lib/tdc/generators.rb +7 -0
- data/lib/tdc/generators/catalog_entries.rb +13 -0
- data/lib/tdc/generators/definition_resolvable.rb +62 -0
- data/lib/tdc/generators/definition_sourcable.rb +52 -0
- data/lib/tdc/generators/generator_base.rb +23 -0
- data/lib/tdc/generators/instance_definition_configurable.rb +60 -0
- data/lib/tdc/generators/singular_generator.rb +43 -0
- data/lib/tdc/generators/standard_generator.rb +28 -0
- data/lib/tdc/in_memory_data_definition.rb +24 -0
- data/lib/tdc/missing_hook_override_error.rb +7 -0
- data/lib/tdc/missing_path_elements_error.rb +3 -0
- data/lib/tdc/missing_test_data_definition_error.rb +3 -0
- data/lib/tdc/non_singular_instance_error.rb +3 -0
- data/lib/tdc/test_data_definition_reader.rb +57 -0
- data/lib/tdc/unresolvable_tag_error.rb +3 -0
- data/lib/tdc/version.rb +3 -0
- data/lib/tdc/with_indifferent_access_decorator.rb +17 -0
- data/lib/tdc/yaml_load_error.rb +3 -0
- data/tdc.gemspec +37 -0
- metadata +173 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 523892b0a0a870a9b4c5a6abe2b7e0cac37b8dfb51249e50da32fcac29c3e6f6
|
4
|
+
data.tar.gz: 616521e4890e99edf594c8b6778b2f4ee7680e713077ba4cf08811b91d4adf26
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e6c1bf80620c67f96f89234a7b578c3a97d42b64a732c1048d489902206f9caa859c998c684f10ac38b87ac67a1cfe11340438708aa391c524381470737265a3
|
7
|
+
data.tar.gz: d1df65063610d080e53cc57f61b64bca1f48111fb99240702547f609c5f8b446b698de6d816b0f4d4e64d7c9813daad466567ee47df759e9fda497f97a8aa6a4
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rspec
|
3
|
+
|
4
|
+
AllCops:
|
5
|
+
TargetRubyVersion: 2.5
|
6
|
+
|
7
|
+
Exclude:
|
8
|
+
- 'bin/**/*'
|
9
|
+
|
10
|
+
Layout/EmptyLinesAroundAttributeAccessor:
|
11
|
+
Enabled: true
|
12
|
+
|
13
|
+
# Rubocop and I cannot agree.
|
14
|
+
Layout/MultilineMethodCallBraceLayout:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Layout/SpaceAroundMethodCallOperator:
|
18
|
+
Enabled: true
|
19
|
+
|
20
|
+
Lint/RaiseException:
|
21
|
+
Enabled: true
|
22
|
+
|
23
|
+
Lint/StructNewOverride:
|
24
|
+
Enabled: true
|
25
|
+
|
26
|
+
Metrics/BlockLength:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
Naming/MemoizedInstanceVariableName:
|
30
|
+
EnforcedStyleForLeadingUnderscores: required
|
31
|
+
|
32
|
+
RSpec/AnyInstance:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
RSpec/ExampleLength:
|
36
|
+
Max: 15
|
37
|
+
|
38
|
+
Metrics/LineLength:
|
39
|
+
Max: 120
|
40
|
+
|
41
|
+
RSpec/DescribeClass:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
RSpec/DescribedClass:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
RSpec/NotToNot:
|
48
|
+
EnforcedStyle: to_not
|
49
|
+
|
50
|
+
RSpec/LeadingSubject:
|
51
|
+
Enabled: false
|
52
|
+
|
53
|
+
RSpec/MessageSpies:
|
54
|
+
Enabled: false
|
55
|
+
|
56
|
+
RSpec/MultipleExpectations:
|
57
|
+
Max: 3
|
58
|
+
|
59
|
+
RSpec/SubjectStub:
|
60
|
+
Enabled: false
|
61
|
+
|
62
|
+
Style/BlockDelimiters:
|
63
|
+
Enabled: true
|
64
|
+
EnforcedStyle: line_count_based
|
65
|
+
BracesRequiredMethods:
|
66
|
+
- 'let'
|
67
|
+
|
68
|
+
Style/Documentation:
|
69
|
+
Enabled: false
|
70
|
+
|
71
|
+
Style/ExponentialNotation:
|
72
|
+
Enabled: true
|
73
|
+
|
74
|
+
# We can ignore this small performance improvement.
|
75
|
+
Style/FrozenStringLiteralComment:
|
76
|
+
Enabled: false
|
77
|
+
|
78
|
+
Style/HashEachMethods:
|
79
|
+
Enabled: true
|
80
|
+
|
81
|
+
Style/HashTransformKeys:
|
82
|
+
Enabled: true
|
83
|
+
|
84
|
+
Style/HashTransformValues:
|
85
|
+
Enabled: true
|
86
|
+
|
87
|
+
# We like to use the hash rocket in rake files.
|
88
|
+
Style/HashSyntax:
|
89
|
+
Exclude:
|
90
|
+
- 'Rakefile'
|
91
|
+
|
92
|
+
# No need to mention StandardError.
|
93
|
+
Style/RescueStandardError:
|
94
|
+
EnforcedStyle: implicit
|
95
|
+
|
96
|
+
Style/SlicingWithRange:
|
97
|
+
Enabled: false
|
98
|
+
|
99
|
+
# We'll just use double quotes everywhere.
|
100
|
+
Style/StringLiterals:
|
101
|
+
EnforcedStyle: double_quotes
|
102
|
+
|
103
|
+
# I prefer not to use %i or %I for an array of symbols.
|
104
|
+
Style/SymbolArray:
|
105
|
+
Enabled: false
|
106
|
+
|
107
|
+
# We are not going to optimize by freezing strings.
|
108
|
+
Style/MutableConstant:
|
109
|
+
Enabled: false
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.6
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## [Unreleased]
|
8
|
+
|
9
|
+
## [0.1.2] - 2020-05-18
|
10
|
+
|
11
|
+
- Complete the extraction from PackManager
|
12
|
+
|
13
|
+
## [0.1.1] - 2020-05-18
|
14
|
+
|
15
|
+
#### New Features
|
16
|
+
|
17
|
+
- Avoid all PackManager dependencies
|
18
|
+
|
19
|
+
|
data/Gemfile
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "tdc"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/tdc.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
require "active_support/core_ext/hash/indifferent_access"
|
5
|
+
|
6
|
+
require "tdc/in_memory_data_definition"
|
7
|
+
require "tdc/test_data_definition_reader"
|
8
|
+
require "tdc/version"
|
9
|
+
require "tdc/with_indifferent_access_decorator"
|
10
|
+
|
11
|
+
require "tdc/generators"
|
12
|
+
require "tdc/generators/catalog_entries"
|
13
|
+
require "tdc/generators/definition_resolvable"
|
14
|
+
require "tdc/generators/definition_sourcable"
|
15
|
+
require "tdc/generators/generator_base"
|
16
|
+
require "tdc/generators/instance_definition_configurable"
|
17
|
+
require "tdc/generators/singular_generator"
|
18
|
+
require "tdc/generators/standard_generator"
|
19
|
+
|
20
|
+
require "tdc/decorator_error"
|
21
|
+
require "tdc/missing_hook_override_error"
|
22
|
+
require "tdc/missing_path_elements_error"
|
23
|
+
require "tdc/missing_test_data_definition_error"
|
24
|
+
require "tdc/non_singular_instance_error"
|
25
|
+
require "tdc/unresolvable_tag_error"
|
26
|
+
require "tdc/yaml_load_error"
|
27
|
+
|
28
|
+
#
|
29
|
+
# A framework for building a Test Data Catalog
|
30
|
+
#
|
31
|
+
module Tdc
|
32
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Tdc
|
2
|
+
module Generators
|
3
|
+
#
|
4
|
+
# Knows how to contain arbitrary collections of model objects. As model instances are created
|
5
|
+
# by generators, the model instances are added to the current catalog as catalog entries.
|
6
|
+
#
|
7
|
+
class CatalogEntries < OpenStruct
|
8
|
+
def add_catalog_entry(tag, entry)
|
9
|
+
send("#{tag}=", entry)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Tdc
|
2
|
+
module Generators
|
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.
|
6
|
+
#
|
7
|
+
# The resolve_tag class macro is provided for generators to define tag resolution.
|
8
|
+
#
|
9
|
+
# Example:
|
10
|
+
#
|
11
|
+
# Suppose a particular instance definition contained { subcomponent: sc_snackers_minis }
|
12
|
+
# then a generator could resolve the subcomponent by defining:
|
13
|
+
#
|
14
|
+
# resolve_tag key: :subcomponent, source: "item_master.items"
|
15
|
+
#
|
16
|
+
module DefinitionResolvable
|
17
|
+
extend ActiveSupport::Concern
|
18
|
+
|
19
|
+
included do
|
20
|
+
class_attribute :_tag_resolvers, instance_writer: false
|
21
|
+
self._tag_resolvers = []
|
22
|
+
end
|
23
|
+
|
24
|
+
class_methods do
|
25
|
+
def resolve_tag(key:, source:)
|
26
|
+
_tag_resolvers << [key, source]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def run_tag_resolvers(instance_definition)
|
31
|
+
_tag_resolvers.each { |key, source| _resolve_tag_reference(instance_definition, key, source) }
|
32
|
+
end
|
33
|
+
|
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__)
|
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::UnresolvableTagError, message
|
55
|
+
end
|
56
|
+
|
57
|
+
# Replace the tag value with the sourced object.
|
58
|
+
instance_definition[key] = sourced_object
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Tdc
|
2
|
+
module Generators
|
3
|
+
#
|
4
|
+
# Creates ghost methods for use in generators.
|
5
|
+
#
|
6
|
+
# All ghost methods are named 'key'_definition where 'key' is a key into the instance_definition hash.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# If an instance definition had "line" and "replenishment_parameters" keys then the following
|
11
|
+
# ghost methods could be used to refer to the value associated with those keys:
|
12
|
+
#
|
13
|
+
# line_definition
|
14
|
+
# replenishment_parameters_definition
|
15
|
+
#
|
16
|
+
module DefinitionSourcable
|
17
|
+
extend ActiveSupport::Concern
|
18
|
+
|
19
|
+
class_methods do
|
20
|
+
def source_definition_from(definition)
|
21
|
+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
22
|
+
def definition_source
|
23
|
+
@definition_source ||= #{definition}
|
24
|
+
end
|
25
|
+
RUBY
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def configure_definition_source(definition)
|
30
|
+
@definition_source = definition
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def method_missing(method, *args)
|
36
|
+
key = transform_method_to_definition_source_key(method)
|
37
|
+
|
38
|
+
definition_source.key?(key) ? definition_source.fetch(key) : super
|
39
|
+
end
|
40
|
+
|
41
|
+
def respond_to_missing?(method, include_all = false)
|
42
|
+
key = transform_method_to_definition_source_key(method)
|
43
|
+
|
44
|
+
definition_source.key?(key) ? true : super
|
45
|
+
end
|
46
|
+
|
47
|
+
def transform_method_to_definition_source_key(method)
|
48
|
+
method.to_s.gsub(/_definition$/, "")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Tdc
|
2
|
+
module Generators
|
3
|
+
#
|
4
|
+
# Abstract base class for all Test Data Catalog generators.
|
5
|
+
#
|
6
|
+
class GeneratorBase
|
7
|
+
attr_reader :data_definition, :current_catalog
|
8
|
+
|
9
|
+
def initialize(data_definition, current_catalog)
|
10
|
+
@data_definition = data_definition
|
11
|
+
@current_catalog = current_catalog
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate
|
15
|
+
raise Tdc::MissingHookOverrideError
|
16
|
+
end
|
17
|
+
|
18
|
+
def instance_definitions
|
19
|
+
raise Tdc::MissingHookOverrideError
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Tdc
|
2
|
+
module Generators
|
3
|
+
#
|
4
|
+
# Knows how to provide a configurable instance definition.
|
5
|
+
#
|
6
|
+
# Shared implementation between the StandardGenerator and the SingularGenerator abstract classes.
|
7
|
+
#
|
8
|
+
module InstanceDefinitionConfigurable
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
include Tdc::Generators::DefinitionSourcable
|
13
|
+
|
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
|
25
|
+
|
26
|
+
def run_resolvers_and_generate_instance
|
27
|
+
run_atx_resolvers(instance_definition)
|
28
|
+
run_tag_resolvers(instance_definition)
|
29
|
+
|
30
|
+
generate_instance
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Hook method: subclasses are expected to define how to generate a model instance.
|
35
|
+
#
|
36
|
+
def generate_instance
|
37
|
+
raise Tdc::MissingHookOverrideError
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Hook method: subclasses may include the DefinitionResolvable concern to override.
|
42
|
+
#
|
43
|
+
def run_tag_resolvers(_instance_definition)
|
44
|
+
# Do nothing
|
45
|
+
end
|
46
|
+
|
47
|
+
def run_atx_resolvers(instance_definition)
|
48
|
+
atx_definitions = instance_definition.select { |k, _v| /_atx$/ =~ k }
|
49
|
+
|
50
|
+
atx_definitions.each do |k, v|
|
51
|
+
# Remove the original _atx attribute.
|
52
|
+
instance_definition.delete(k)
|
53
|
+
|
54
|
+
# Add a standard _at attribute.
|
55
|
+
instance_definition[k.delete_suffix("x")] = eval(v) # rubocop:disable Security/Eval
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Tdc
|
2
|
+
module Generators
|
3
|
+
#
|
4
|
+
# Abstract class for defining generators that define a single model instance.
|
5
|
+
#
|
6
|
+
# See also StandardGenerator.
|
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
|
+
|
17
|
+
def with_definition(additional_definitions)
|
18
|
+
@additional_definitions = additional_definitions.stringify_keys.reject { |_, v| v == :missing_definition }
|
19
|
+
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def generate
|
24
|
+
configure_instance_definition(singular_instance_definition.merge(@additional_definitions))
|
25
|
+
|
26
|
+
run_resolvers_and_generate_instance
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def singular_instance_definition
|
32
|
+
all_instance_definitions = instance_definitions
|
33
|
+
|
34
|
+
if all_instance_definitions.many?
|
35
|
+
raise Tdc::NonSingularInstanceError, "For the moment we only generate a single model instance"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Delete the tag so that the models do not need to filter it out.
|
39
|
+
all_instance_definitions.first.except("tag")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Tdc
|
2
|
+
module Generators
|
3
|
+
#
|
4
|
+
# Abstract class for defining generators that define a collection of model instances.
|
5
|
+
#
|
6
|
+
# See also SingularGenerator.
|
7
|
+
#
|
8
|
+
class StandardGenerator < Tdc::Generators::GeneratorBase
|
9
|
+
include Tdc::Generators::InstanceDefinitionConfigurable
|
10
|
+
|
11
|
+
def generate
|
12
|
+
CatalogEntries.new.tap do |catalog_entries|
|
13
|
+
instance_definitions.each do |instance_definition|
|
14
|
+
configure_instance_definition(instance_definition)
|
15
|
+
|
16
|
+
# Delete the tag so that the models do not need to filter it out.
|
17
|
+
tag = instance_definition.delete("tag")
|
18
|
+
|
19
|
+
generated = run_resolvers_and_generate_instance
|
20
|
+
|
21
|
+
# Add generated instance to the catalog entries whenever a tag provided.
|
22
|
+
catalog_entries.add_catalog_entry(tag, generated) if tag
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Tdc
|
2
|
+
#
|
3
|
+
# Knows how to read test data definitions from an in-memory representation.
|
4
|
+
#
|
5
|
+
class InMemoryDataDefinition
|
6
|
+
def initialize(path_elements_data = {})
|
7
|
+
@store = path_elements_data
|
8
|
+
end
|
9
|
+
|
10
|
+
def store(path_elements, data)
|
11
|
+
@store[path_elements] = data
|
12
|
+
end
|
13
|
+
|
14
|
+
def read(*path_elements)
|
15
|
+
@store.fetch(path_elements) do
|
16
|
+
raise MissingPathElementsError, "The path did not have any data associated with it: #{path_elements.inspect}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def with_indifferent_access
|
21
|
+
self.extend(Tdc::WithIndifferentAccessDecorator) # rubocop:disable Style/RedundantSelf
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Tdc
|
2
|
+
#
|
3
|
+
# Knows how to read test data definitions from YAML files.
|
4
|
+
#
|
5
|
+
class TestDataDefinitionReader
|
6
|
+
EMPTY_DEFINITIONS = []
|
7
|
+
|
8
|
+
def initialize(catalog_root_directory)
|
9
|
+
@catalog_root_directory = catalog_root_directory
|
10
|
+
end
|
11
|
+
|
12
|
+
def read(*path_elements)
|
13
|
+
data_definition_from(definitions_file(path_elements))
|
14
|
+
end
|
15
|
+
|
16
|
+
def with_indifferent_access
|
17
|
+
self.extend(Tdc::WithIndifferentAccessDecorator) # rubocop:disable Style/RedundantSelf
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def definitions_file(path_elements)
|
23
|
+
fully_qualified_path_elements = [@catalog_root_directory].concat(path_elements.map(&:to_s))
|
24
|
+
|
25
|
+
fully_qualified_path_elements.last.concat(".yml")
|
26
|
+
|
27
|
+
File.join(*fully_qualified_path_elements)
|
28
|
+
end
|
29
|
+
|
30
|
+
def data_definition_from(definitions_file)
|
31
|
+
if File.exist?(definitions_file)
|
32
|
+
load_yaml(definitions_file) || EMPTY_DEFINITIONS
|
33
|
+
else
|
34
|
+
missing_data_definition(definitions_file)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_yaml(definitions_file)
|
39
|
+
YAML.load(expand_erb(definitions_file)) # rubocop:disable Security/YAMLLoad
|
40
|
+
rescue => e
|
41
|
+
raise Tdc::YamlLoadError, <<~MSG
|
42
|
+
Unable to load YAML from #{definitions_file}
|
43
|
+
Cause: #{e.message}"
|
44
|
+
MSG
|
45
|
+
end
|
46
|
+
|
47
|
+
def expand_erb(definitions_file)
|
48
|
+
ERB.new(File.read(definitions_file)).result
|
49
|
+
end
|
50
|
+
|
51
|
+
def missing_data_definition(definitions_file)
|
52
|
+
return EMPTY_DEFINITIONS if ENV.key?("TDC_IGNORE_MISSING_TEST_DATA_DEFINITION_ERROR")
|
53
|
+
|
54
|
+
raise MissingTestDataDefinitionError, definitions_file
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/tdc/version.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Tdc
|
2
|
+
#
|
3
|
+
# Knows how to transform the result of calling the TestDefinitionReader#read method from an Array
|
4
|
+
# of Hash instances into an Array of ActiveSupport::HashWithIndifferentAccess instances.
|
5
|
+
#
|
6
|
+
module WithIndifferentAccessDecorator
|
7
|
+
def read(*path_elements)
|
8
|
+
definitions = super
|
9
|
+
|
10
|
+
raise DecoratorError, "Use 'with_indifferent_access' only for an Array" unless definitions.is_a?(Array)
|
11
|
+
|
12
|
+
definitions.map do |definition|
|
13
|
+
definition.is_a?(Hash) ? ActiveSupport::HashWithIndifferentAccess.new(definition) : definition
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/tdc.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative "lib/tdc/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "tdc"
|
5
|
+
spec.version = Tdc::VERSION
|
6
|
+
spec.authors = ["Alistair McKinnell"]
|
7
|
+
spec.email = ["alistairm@nulogy.com"]
|
8
|
+
|
9
|
+
spec.summary = "A simple framework for creating a Test Data Catalog"
|
10
|
+
spec.homepage = "https://github.com/nulogy/tdc"
|
11
|
+
|
12
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
13
|
+
|
14
|
+
spec.metadata = {
|
15
|
+
"homepage_uri" => "https://github.com/nulogy/tdc",
|
16
|
+
"changelog_uri" => "https://github.com/nulogy/tdc/blob/master/CHANGELOG.md",
|
17
|
+
"source_code_uri" => "https://github.com/nulogy/tdc",
|
18
|
+
"bug_tracker_uri" => "https://github.com/nulogy/tdc/issues"
|
19
|
+
}
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
end
|
26
|
+
spec.bindir = "exe"
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
spec.add_runtime_dependency "activesupport", "~> 5.2.4"
|
31
|
+
|
32
|
+
spec.add_development_dependency "rake", ">= 12.1", "< 13.1"
|
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"
|
36
|
+
spec.add_development_dependency "simplecov", "~> 0.17"
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tdc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alistair McKinnell
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-05-19 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: 5.2.4
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.2.4
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '12.1'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '13.1'
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '12.1'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '13.1'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.9'
|
54
|
+
- - "<"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '4.0'
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '3.9'
|
64
|
+
- - "<"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '4.0'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: rubocop
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0.82'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0.82'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rubocop-rspec
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - "~>"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '1.38'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '1.38'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: simplecov
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - "~>"
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0.17'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - "~>"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0.17'
|
109
|
+
description:
|
110
|
+
email:
|
111
|
+
- alistairm@nulogy.com
|
112
|
+
executables: []
|
113
|
+
extensions: []
|
114
|
+
extra_rdoc_files: []
|
115
|
+
files:
|
116
|
+
- ".gitignore"
|
117
|
+
- ".rspec"
|
118
|
+
- ".rubocop.yml"
|
119
|
+
- ".ruby-version"
|
120
|
+
- CHANGELOG.md
|
121
|
+
- Gemfile
|
122
|
+
- README.md
|
123
|
+
- Rakefile
|
124
|
+
- bin/console
|
125
|
+
- bin/setup
|
126
|
+
- lib/tdc.rb
|
127
|
+
- lib/tdc/decorator_error.rb
|
128
|
+
- lib/tdc/generators.rb
|
129
|
+
- lib/tdc/generators/catalog_entries.rb
|
130
|
+
- lib/tdc/generators/definition_resolvable.rb
|
131
|
+
- lib/tdc/generators/definition_sourcable.rb
|
132
|
+
- lib/tdc/generators/generator_base.rb
|
133
|
+
- lib/tdc/generators/instance_definition_configurable.rb
|
134
|
+
- lib/tdc/generators/singular_generator.rb
|
135
|
+
- lib/tdc/generators/standard_generator.rb
|
136
|
+
- lib/tdc/in_memory_data_definition.rb
|
137
|
+
- lib/tdc/missing_hook_override_error.rb
|
138
|
+
- lib/tdc/missing_path_elements_error.rb
|
139
|
+
- lib/tdc/missing_test_data_definition_error.rb
|
140
|
+
- lib/tdc/non_singular_instance_error.rb
|
141
|
+
- lib/tdc/test_data_definition_reader.rb
|
142
|
+
- lib/tdc/unresolvable_tag_error.rb
|
143
|
+
- lib/tdc/version.rb
|
144
|
+
- lib/tdc/with_indifferent_access_decorator.rb
|
145
|
+
- lib/tdc/yaml_load_error.rb
|
146
|
+
- tdc.gemspec
|
147
|
+
homepage: https://github.com/nulogy/tdc
|
148
|
+
licenses: []
|
149
|
+
metadata:
|
150
|
+
homepage_uri: https://github.com/nulogy/tdc
|
151
|
+
changelog_uri: https://github.com/nulogy/tdc/blob/master/CHANGELOG.md
|
152
|
+
source_code_uri: https://github.com/nulogy/tdc
|
153
|
+
bug_tracker_uri: https://github.com/nulogy/tdc/issues
|
154
|
+
post_install_message:
|
155
|
+
rdoc_options: []
|
156
|
+
require_paths:
|
157
|
+
- lib
|
158
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: 2.5.0
|
163
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
requirements: []
|
169
|
+
rubygems_version: 3.1.3
|
170
|
+
signing_key:
|
171
|
+
specification_version: 4
|
172
|
+
summary: A simple framework for creating a Test Data Catalog
|
173
|
+
test_files: []
|