fabrication 2.21.0 → 3.0.0.beta.1.1
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 +4 -4
- data/README.markdown +1 -4
- data/Rakefile +8 -10
- data/lib/fabricate.rb +10 -13
- data/lib/fabrication.rb +4 -9
- data/lib/fabrication/config.rb +23 -22
- data/lib/fabrication/cucumber/step_fabricator.rb +20 -13
- data/lib/fabrication/errors/duplicate_fabricator_error.rb +5 -3
- data/lib/fabrication/errors/infinite_recursion_error.rb +5 -3
- data/lib/fabrication/errors/misplaced_fabricate_error.rb +7 -3
- data/lib/fabrication/errors/unfabricatable_error.rb +5 -4
- data/lib/fabrication/errors/unknown_fabricator_error.rb +5 -5
- data/lib/fabrication/generator/active_record.rb +18 -15
- data/lib/fabrication/generator/base.rb +93 -81
- data/lib/fabrication/generator/sequel.rb +29 -27
- data/lib/fabrication/railtie.rb +1 -3
- data/lib/fabrication/schematic/attribute.rb +69 -62
- data/lib/fabrication/schematic/definition.rb +139 -134
- data/lib/fabrication/schematic/evaluator.rb +61 -54
- data/lib/fabrication/schematic/manager.rb +67 -59
- data/lib/fabrication/schematic/runner.rb +12 -9
- data/lib/fabrication/sequencer.rb +23 -22
- data/lib/fabrication/support.rb +57 -54
- data/lib/fabrication/syntax/make.rb +0 -1
- data/lib/fabrication/transform.rb +34 -36
- data/lib/fabrication/version.rb +1 -1
- data/lib/rails/generators/fabrication/cucumber_steps/cucumber_steps_generator.rb +2 -3
- data/lib/rails/generators/fabrication/cucumber_steps/templates/fabrication_steps.rb +10 -10
- data/lib/rails/generators/fabrication/model/model_generator.rb +9 -9
- data/lib/tasks/defined_fabricators.rake +11 -11
- metadata +10 -12
- data/lib/fabrication/generator/data_mapper.rb +0 -17
- data/lib/fabrication/generator/mongoid.rb +0 -15
@@ -1,70 +1,77 @@
|
|
1
|
-
|
1
|
+
module Fabrication
|
2
|
+
module Schematic
|
3
|
+
class Evaluator < BasicObject
|
4
|
+
def process(definition, &block)
|
5
|
+
@_definition = definition
|
6
|
+
instance_eval(&block)
|
7
|
+
end
|
2
8
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
end
|
9
|
+
def respond_to_missing?(_method_name, _include_private = false)
|
10
|
+
true
|
11
|
+
end
|
7
12
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
def method_missing(method_name, *args, &block)
|
14
|
+
params = ::Fabrication::Support.extract_options!(args)
|
15
|
+
value = args.first
|
16
|
+
block = @_definition.generate_value(method_name, params) if args.empty? && !block
|
17
|
+
@_definition.append_or_update_attribute(method_name, value, params, &block)
|
18
|
+
end
|
14
19
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
def after_build(&block)
|
21
|
+
@_definition.callbacks[:after_build] ||= []
|
22
|
+
@_definition.callbacks[:after_build] << block
|
23
|
+
end
|
19
24
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
25
|
+
def before_validation(&block)
|
26
|
+
@_definition.callbacks[:before_validation] ||= []
|
27
|
+
@_definition.callbacks[:before_validation] << block
|
28
|
+
end
|
24
29
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
30
|
+
def after_validation(&block)
|
31
|
+
@_definition.callbacks[:after_validation] ||= []
|
32
|
+
@_definition.callbacks[:after_validation] << block
|
33
|
+
end
|
29
34
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
35
|
+
def before_save(&block)
|
36
|
+
@_definition.callbacks[:before_save] ||= []
|
37
|
+
@_definition.callbacks[:before_save] << block
|
38
|
+
end
|
34
39
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
40
|
+
def before_create(&block)
|
41
|
+
@_definition.callbacks[:before_create] ||= []
|
42
|
+
@_definition.callbacks[:before_create] << block
|
43
|
+
end
|
39
44
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
45
|
+
def after_create(&block)
|
46
|
+
@_definition.callbacks[:after_create] ||= []
|
47
|
+
@_definition.callbacks[:after_create] << block
|
48
|
+
end
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
50
|
+
def after_save(&block)
|
51
|
+
@_definition.callbacks[:after_save] ||= []
|
52
|
+
@_definition.callbacks[:after_save] << block
|
53
|
+
end
|
49
54
|
|
50
|
-
|
51
|
-
|
52
|
-
|
55
|
+
def on_init(&block)
|
56
|
+
@_definition.callbacks[:on_init] = block
|
57
|
+
end
|
53
58
|
|
54
|
-
|
55
|
-
|
56
|
-
|
59
|
+
def initialize_with(&block)
|
60
|
+
@_definition.callbacks[:initialize_with] = block
|
61
|
+
end
|
57
62
|
|
58
|
-
|
59
|
-
|
60
|
-
|
63
|
+
def init_with(*args)
|
64
|
+
args
|
65
|
+
end
|
61
66
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
67
|
+
def transient(*field_names)
|
68
|
+
field_names.each do |field_name|
|
69
|
+
if field_name.is_a?(::Hash)
|
70
|
+
field_name.each_pair { |name, value| @_definition.append_or_update_attribute(name, value, transient: true) }
|
71
|
+
else
|
72
|
+
@_definition.append_or_update_attribute(field_name, nil, transient: true)
|
73
|
+
end
|
74
|
+
end
|
68
75
|
end
|
69
76
|
end
|
70
77
|
end
|
@@ -1,80 +1,88 @@
|
|
1
1
|
require 'singleton'
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
module Fabrication
|
4
|
+
module Schematic
|
5
|
+
class Manager
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
def preinitialize
|
9
|
+
@initializing = true
|
10
|
+
clear
|
11
|
+
end
|
5
12
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
13
|
+
def initializing?
|
14
|
+
@initializing ||= nil
|
15
|
+
end
|
10
16
|
|
11
|
-
|
12
|
-
|
13
|
-
|
17
|
+
def schematics
|
18
|
+
@schematics ||= {}
|
19
|
+
end
|
14
20
|
|
15
|
-
|
16
|
-
|
17
|
-
|
21
|
+
def clear
|
22
|
+
schematics.clear
|
23
|
+
end
|
18
24
|
|
19
|
-
|
20
|
-
|
25
|
+
def empty?
|
26
|
+
schematics.empty?
|
27
|
+
end
|
21
28
|
|
22
|
-
|
23
|
-
|
24
|
-
|
29
|
+
def freeze
|
30
|
+
@initializing = false
|
31
|
+
end
|
25
32
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
33
|
+
def register(name, options, &block)
|
34
|
+
name = name.to_sym
|
35
|
+
raise_if_registered(name)
|
36
|
+
store(name, Array(options.delete(:aliases)), options, &block)
|
37
|
+
end
|
31
38
|
|
32
|
-
|
33
|
-
|
34
|
-
|
39
|
+
def [](name)
|
40
|
+
schematics[name.to_sym]
|
41
|
+
end
|
35
42
|
|
36
|
-
|
37
|
-
|
38
|
-
|
43
|
+
def create_stack
|
44
|
+
@create_stack ||= []
|
45
|
+
end
|
39
46
|
|
40
|
-
|
41
|
-
|
42
|
-
|
47
|
+
def build_stack
|
48
|
+
@build_stack ||= []
|
49
|
+
end
|
43
50
|
|
44
|
-
|
45
|
-
|
46
|
-
|
51
|
+
def to_params_stack
|
52
|
+
@to_params_stack ||= []
|
53
|
+
end
|
47
54
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
55
|
+
def load_definitions
|
56
|
+
preinitialize
|
57
|
+
Fabrication::Config.path_prefixes.each do |prefix|
|
58
|
+
Fabrication::Config.fabricator_paths.each do |folder|
|
59
|
+
Dir.glob(File.join(prefix.to_s, folder, '**', '*.rb')).sort.each do |file|
|
60
|
+
load file
|
61
|
+
end
|
62
|
+
end
|
54
63
|
end
|
64
|
+
rescue StandardError => e
|
65
|
+
raise e
|
66
|
+
ensure
|
67
|
+
freeze
|
55
68
|
end
|
56
|
-
end
|
57
|
-
rescue Exception => e
|
58
|
-
raise e
|
59
|
-
ensure
|
60
|
-
freeze
|
61
|
-
end
|
62
69
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
70
|
+
def prevent_recursion!
|
71
|
+
(create_stack + build_stack + to_params_stack).group_by(&:to_sym).each do |name, values|
|
72
|
+
raise Fabrication::InfiniteRecursionError, name if values.length > Fabrication::Config.recursion_limit
|
73
|
+
end
|
74
|
+
end
|
68
75
|
|
69
|
-
|
76
|
+
protected
|
70
77
|
|
71
|
-
|
72
|
-
|
73
|
-
|
78
|
+
def raise_if_registered(name)
|
79
|
+
(raise Fabrication::DuplicateFabricatorError, name) if self[name]
|
80
|
+
end
|
74
81
|
|
75
|
-
|
76
|
-
|
77
|
-
|
82
|
+
def store(name, aliases, options, &block)
|
83
|
+
schematic = schematics[name] = Fabrication::Schematic::Definition.new(name, options, &block)
|
84
|
+
aliases.each { |as| schematics[as.to_sym] = schematic }
|
85
|
+
end
|
86
|
+
end
|
78
87
|
end
|
79
|
-
|
80
88
|
end
|
@@ -1,13 +1,16 @@
|
|
1
|
-
|
1
|
+
module Fabrication
|
2
|
+
module Schematic
|
3
|
+
class Runner
|
4
|
+
attr_accessor :klass
|
2
5
|
|
3
|
-
|
6
|
+
def initialize(klass)
|
7
|
+
self.klass = klass
|
8
|
+
end
|
4
9
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
name = "#{klass.to_s.downcase.gsub(/::/, '_')}_#{name}"
|
11
|
-
Fabrication::Sequencer.sequence(name, start, &block)
|
10
|
+
def sequence(name = Fabrication::Sequencer::DEFAULT, start = nil, &block)
|
11
|
+
name = "#{klass.to_s.downcase.gsub(/::/, '_')}_#{name}"
|
12
|
+
Fabrication::Sequencer.sequence(name, start, &block)
|
13
|
+
end
|
14
|
+
end
|
12
15
|
end
|
13
16
|
end
|
@@ -1,29 +1,30 @@
|
|
1
|
-
|
1
|
+
module Fabrication
|
2
|
+
class Sequencer
|
3
|
+
DEFAULT = :_default
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
sequences[name] += 1
|
5
|
+
def self.sequence(name = DEFAULT, start = nil, &block)
|
6
|
+
idx = sequences[name] ||= start || Fabrication::Config.sequence_start
|
7
|
+
if block_given?
|
8
|
+
sequence_blocks[name] = block.to_proc
|
9
|
+
else
|
10
|
+
sequence_blocks[name] ||= ->(i) { i }
|
11
|
+
end.call(idx).tap do
|
12
|
+
sequences[name] += 1
|
13
|
+
end
|
13
14
|
end
|
14
|
-
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
def self.sequences
|
17
|
+
@sequences ||= {}
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
def self.sequence_blocks
|
21
|
+
@sequence_blocks ||= {}
|
22
|
+
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
def self.reset
|
25
|
+
Fabrication::Config.sequence_start = nil
|
26
|
+
@sequences = nil
|
27
|
+
@sequence_blocks = nil
|
28
|
+
end
|
28
29
|
end
|
29
30
|
end
|
data/lib/fabrication/support.rb
CHANGED
@@ -1,70 +1,73 @@
|
|
1
|
-
|
1
|
+
module Fabrication
|
2
|
+
class Support
|
3
|
+
class << self
|
4
|
+
def fabricatable?(name)
|
5
|
+
Fabrication.manager[name] || class_for(name)
|
6
|
+
end
|
2
7
|
|
3
|
-
|
8
|
+
def class_for(class_or_to_s)
|
9
|
+
class_name = variable_name_to_class_name(class_or_to_s)
|
10
|
+
constantize(class_name)
|
11
|
+
rescue NameError => e
|
12
|
+
raise Fabrication::UnfabricatableError.new(class_or_to_s, e)
|
13
|
+
end
|
4
14
|
|
5
|
-
|
6
|
-
|
7
|
-
|
15
|
+
def constantize(camel_cased_word)
|
16
|
+
names = camel_cased_word.split('::')
|
17
|
+
Object.const_get(camel_cased_word) if names.empty?
|
18
|
+
names.shift if names.size > 1 && names.first.empty?
|
19
|
+
names.inject(Object) do |constant, name|
|
20
|
+
if constant == Object
|
21
|
+
constant.const_get(name)
|
22
|
+
else
|
23
|
+
candidate = constant.const_get(name)
|
24
|
+
next candidate if constant.const_defined?(name, false)
|
25
|
+
next candidate unless Object.const_defined?(name)
|
8
26
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
rescue NameError => original_error
|
13
|
-
raise Fabrication::UnfabricatableError.new(class_or_to_s, original_error)
|
14
|
-
end
|
27
|
+
constant = constant.ancestors.inject do |const, ancestor|
|
28
|
+
break const if ancestor == Object
|
29
|
+
break ancestor if ancestor.const_defined?(name, false)
|
15
30
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
names.shift if names.size > 1 && names.first.empty?
|
20
|
-
names.inject(Object) do |constant, name|
|
21
|
-
if constant == Object
|
22
|
-
constant.const_get(name)
|
23
|
-
else
|
24
|
-
candidate = constant.const_get(name)
|
25
|
-
next candidate if constant.const_defined?(name, false)
|
26
|
-
next candidate unless Object.const_defined?(name)
|
27
|
-
constant = constant.ancestors.inject do |const, ancestor|
|
28
|
-
break const if ancestor == Object
|
29
|
-
break ancestor if ancestor.const_defined?(name, false)
|
30
|
-
const
|
31
|
+
const
|
32
|
+
end
|
33
|
+
constant.const_get(name, false)
|
31
34
|
end
|
32
|
-
constant.const_get(name, false)
|
33
35
|
end
|
34
36
|
end
|
35
|
-
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
def extract_options!(args)
|
39
|
+
args.last.is_a?(::Hash) ? args.pop : {}
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
end
|
42
|
+
def variable_name_to_class_name(name)
|
43
|
+
name_string = name.to_s
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
if name_string.respond_to?(:camelize)
|
46
|
+
name_string.camelize
|
47
|
+
else
|
48
|
+
name_string.gsub(%r{/(.?)}) do
|
49
|
+
"::#{Regexp.last_match(1).upcase}"
|
50
|
+
end.gsub(/(?:^|_)(.)/) { Regexp.last_match(1).upcase }
|
51
|
+
end
|
52
|
+
end
|
49
53
|
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
def hash_class
|
55
|
+
@hash_class ||= defined?(HashWithIndifferentAccess) ? HashWithIndifferentAccess : Hash
|
56
|
+
end
|
53
57
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
58
|
+
def singularize(string)
|
59
|
+
string.singularize
|
60
|
+
rescue StandardError
|
61
|
+
string.end_with?('s') ? string[0..-2] : string
|
62
|
+
end
|
59
63
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
def underscore(string)
|
65
|
+
string.gsub(/::/, '/')
|
66
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
67
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
68
|
+
.tr('-', '_')
|
69
|
+
.downcase
|
70
|
+
end
|
66
71
|
end
|
67
|
-
|
68
72
|
end
|
69
|
-
|
70
73
|
end
|