nakajima-fixjour 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/fixjour/builders.rb +10 -50
- data/lib/fixjour/definitions.rb +36 -0
- data/lib/fixjour/errors.rb +5 -1
- data/lib/fixjour/generator.rb +27 -0
- data/lib/fixjour/overrides_hash.rb +2 -2
- data/lib/fixjour/redundant_check.rb +4 -0
- data/lib/fixjour/verify.rb +24 -4
- data/lib/fixjour.rb +3 -0
- metadata +6 -4
data/lib/fixjour/builders.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
module Fixjour
|
2
2
|
class << self
|
3
|
+
include Definitions
|
4
|
+
|
3
5
|
attr_accessor :allow_redundancy
|
4
|
-
|
6
|
+
|
5
7
|
# The list of classes that have builders defined.
|
6
8
|
def builders
|
7
9
|
@builders ||= Set.new
|
@@ -19,19 +21,19 @@ module Fixjour
|
|
19
21
|
klass.new(options.merge(overrides))
|
20
22
|
end
|
21
23
|
end
|
22
|
-
|
24
|
+
|
23
25
|
name = name_for(klass)
|
24
|
-
|
26
|
+
|
25
27
|
define_create(name)
|
26
28
|
define_valid_attributes(name)
|
27
29
|
end
|
28
|
-
|
30
|
+
|
29
31
|
# Adds builders to Fixjour.
|
30
32
|
def evaluate(&block)
|
31
33
|
begin
|
32
34
|
module_eval(&block)
|
33
35
|
rescue NameError => e
|
34
|
-
if evaluator.respond_to?(e.name)
|
36
|
+
if e.name && evaluator.respond_to?(e.name)
|
35
37
|
raise NonBlockBuilderReference.new("You must use a builder block in order to reference other Fixjour creation methods.")
|
36
38
|
else
|
37
39
|
raise e
|
@@ -46,9 +48,9 @@ module Fixjour
|
|
46
48
|
when String, Symbol then builders.map(&:name).include?(builder)
|
47
49
|
end
|
48
50
|
end
|
49
|
-
|
51
|
+
|
50
52
|
private
|
51
|
-
|
53
|
+
|
52
54
|
# Registers a class' builder. This allows us to make sure
|
53
55
|
# redundant builders aren't defined, which can lead to confusion
|
54
56
|
# when trying to figure out where objects are being created.
|
@@ -57,53 +59,11 @@ module Fixjour
|
|
57
59
|
raise RedundantBuilder.new("You already defined a builder for #{klass.inspect}")
|
58
60
|
end
|
59
61
|
end
|
60
|
-
|
62
|
+
|
61
63
|
def name_for(klass)
|
62
64
|
klass.name.underscore
|
63
65
|
end
|
64
|
-
|
65
|
-
# Defines the new_* method
|
66
|
-
def define_new(klass, &block)
|
67
|
-
name = name_for(klass)
|
68
|
-
define_method("new_#{name}") do |*args|
|
69
|
-
overrides = OverridesHash.new(args.first || { })
|
70
|
-
|
71
|
-
args = case block.arity
|
72
|
-
when 1 then [overrides]
|
73
|
-
when 2 then [MergingProxy.new(klass, overrides), overrides]
|
74
|
-
end
|
75
|
-
|
76
|
-
result = block.bind(self).call(*args)
|
77
|
-
result
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Defines the create_* method
|
82
|
-
def define_create(name)
|
83
|
-
define_method("create_#{name}") do |*args|
|
84
|
-
model = send("new_#{name}", *args)
|
85
|
-
model.save!
|
86
|
-
model
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# Defines the valid_*_attributes method
|
91
|
-
def define_valid_attributes(name)
|
92
|
-
define_method("valid_#{name}_attributes") do |*args|
|
93
|
-
if instance_variable_get("@__valid_#{name}_attrs").nil?
|
94
|
-
valid_attributes = send("new_#{name}").attributes
|
95
|
-
valid_attributes.delete_if { |key, value| value.nil? }
|
96
|
-
instance_variable_set("@__valid_#{name}_attrs", valid_attributes)
|
97
|
-
end
|
98
66
|
|
99
|
-
overrides = args.extract_options!
|
100
|
-
attrs = instance_variable_get("@__valid_#{name}_attrs").merge(overrides)
|
101
|
-
attrs.stringify_keys!
|
102
|
-
attrs.make_indifferent!
|
103
|
-
attrs
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
67
|
# Anonymous class used for reflecting on current Fixjour state.
|
108
68
|
def evaluator
|
109
69
|
@evaluator ||= begin
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Fixjour
|
2
|
+
module Definitions
|
3
|
+
# Defines the new_* method
|
4
|
+
def define_new(klass, &block)
|
5
|
+
define_method("new_#{name_for(klass)}") do |*args|
|
6
|
+
Generator.new(klass, block).call(self, args.extract_options!)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Defines the create_* method
|
11
|
+
def define_create(name)
|
12
|
+
define_method("create_#{name}") do |*args|
|
13
|
+
model = send("new_#{name}", *args)
|
14
|
+
model.save!
|
15
|
+
model
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Defines the valid_*_attributes method
|
20
|
+
def define_valid_attributes(name)
|
21
|
+
define_method("valid_#{name}_attributes") do |*args|
|
22
|
+
if instance_variable_get("@__valid_#{name}_attrs").nil?
|
23
|
+
valid_attributes = send("new_#{name}").attributes
|
24
|
+
valid_attributes.delete_if { |key, value| value.nil? }
|
25
|
+
instance_variable_set("@__valid_#{name}_attrs", valid_attributes)
|
26
|
+
end
|
27
|
+
|
28
|
+
overrides = args.extract_options!
|
29
|
+
attrs = instance_variable_get("@__valid_#{name}_attrs").merge(overrides)
|
30
|
+
attrs.stringify_keys!
|
31
|
+
attrs.make_indifferent!
|
32
|
+
attrs
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/fixjour/errors.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
module Fixjour
|
2
|
-
# Raised when a builder returns an invalid object
|
2
|
+
# Raised when a builder returns an invalid object.
|
3
3
|
class InvalidBuilder < StandardError; end
|
4
4
|
|
5
|
+
# Raised when a builder will return an invalid object
|
6
|
+
# due to a validates_uniqueness_of validation.
|
7
|
+
class DangerousBuilder < StandardError; end
|
8
|
+
|
5
9
|
# Raised when a builder returns an object of the wrong type
|
6
10
|
class WrongBuilderType < StandardError; end
|
7
11
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Fixjour
|
2
|
+
# This generates a new instance of a model object for
|
3
|
+
# the new_[model] method.
|
4
|
+
class Generator
|
5
|
+
attr_reader :klass, :block
|
6
|
+
|
7
|
+
def initialize(klass, block)
|
8
|
+
@klass, @block = klass, block
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(context, overrides={})
|
12
|
+
overrides = OverridesHash.new(overrides)
|
13
|
+
result = block.bind(context).call(*args(overrides))
|
14
|
+
case result
|
15
|
+
when Hash then klass.new(result.merge(overrides))
|
16
|
+
else result
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def args(overrides)
|
21
|
+
case block.arity
|
22
|
+
when 1 then [overrides]
|
23
|
+
when 2 then [MergingProxy.new(klass, overrides), overrides]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -12,8 +12,8 @@ module Fixjour
|
|
12
12
|
# Allows for processing of the overrides hash. Deletes
|
13
13
|
# the option when it's present, then yields the value.
|
14
14
|
def process(option)
|
15
|
-
|
16
|
-
yield value if block_given?
|
15
|
+
delete(option).tap do |value|
|
16
|
+
yield value if value and block_given?
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -3,6 +3,10 @@ module Fixjour
|
|
3
3
|
klass.extend(RedundancyChecker)
|
4
4
|
end
|
5
5
|
|
6
|
+
# Uses method_added hook to make sure no redundant builder methods
|
7
|
+
# get defined after a builder has already created them. For example,
|
8
|
+
# if you have a Comment builder, this hook will ensure that any attempt
|
9
|
+
# to define a #new_comment method will raise an exception.
|
6
10
|
module RedundancyChecker
|
7
11
|
BUILDER_METHOD_PATTERN = /^(new|create|valid)_(\w+)(_attributes)?$/
|
8
12
|
|
data/lib/fixjour/verify.rb
CHANGED
@@ -7,20 +7,40 @@ module Fixjour
|
|
7
7
|
# * The creation methods return objects of the proper type
|
8
8
|
def verify!
|
9
9
|
builders.each do |klass|
|
10
|
-
result =
|
10
|
+
result = new_record(klass)
|
11
11
|
|
12
12
|
unless result.valid?
|
13
|
-
|
13
|
+
error(klass, InvalidBuilder, "returns an invalid object: #{result.errors.inspect}")
|
14
14
|
end
|
15
15
|
|
16
16
|
unless result.new_record?
|
17
|
-
|
17
|
+
error(klass, BuilderSavedRecord, "must return a new record")
|
18
18
|
end
|
19
19
|
|
20
20
|
unless result.is_a?(klass)
|
21
|
-
|
21
|
+
error(klass, WrongBuilderType, "must return an instance of #{klass}")
|
22
|
+
end
|
23
|
+
|
24
|
+
result.save!
|
25
|
+
|
26
|
+
unless new_record(klass).valid?
|
27
|
+
msg = ""
|
28
|
+
msg << "returns invalid an invalid object after another object has been saved.\n"
|
29
|
+
msg << "This could be caused by a validates_uniqueness_of validation in your model.\n"
|
30
|
+
msg << "Use something like the faker gem to alleviate this issue."
|
31
|
+
error(klass, DangerousBuilder, msg)
|
22
32
|
end
|
23
33
|
end
|
24
34
|
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def error(klass, exception, msg)
|
39
|
+
raise exception.new("The builder for #{klass} #{msg} ")
|
40
|
+
end
|
41
|
+
|
42
|
+
def new_record(klass)
|
43
|
+
evaluator.send("new_#{name_for(klass)}")
|
44
|
+
end
|
25
45
|
end
|
26
46
|
end
|
data/lib/fixjour.rb
CHANGED
@@ -3,11 +3,14 @@ $LOAD_PATH << File.dirname(__FILE__)
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'activerecord'
|
5
5
|
require 'core_ext/hash'
|
6
|
+
require 'core_ext/object'
|
6
7
|
require 'fixjour/merging_proxy'
|
7
8
|
require 'fixjour/redundant_check'
|
8
9
|
require 'fixjour/overrides_hash'
|
9
10
|
require 'fixjour/verify'
|
10
11
|
require 'fixjour/errors'
|
12
|
+
require 'fixjour/generator'
|
13
|
+
require 'fixjour/definitions'
|
11
14
|
require 'fixjour/builders'
|
12
15
|
|
13
16
|
# This method is just for prettiness
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nakajima-fixjour
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pat Nakajima
|
@@ -34,11 +34,13 @@ files:
|
|
34
34
|
- lib/core_ext/hash.rb
|
35
35
|
- lib/fixjour
|
36
36
|
- lib/fixjour/builders.rb
|
37
|
-
- lib/fixjour/
|
37
|
+
- lib/fixjour/definitions.rb
|
38
38
|
- lib/fixjour/errors.rb
|
39
|
-
- lib/fixjour/
|
40
|
-
- lib/fixjour/
|
39
|
+
- lib/fixjour/generator.rb
|
40
|
+
- lib/fixjour/merging_proxy.rb
|
41
41
|
- lib/fixjour/overrides_hash.rb
|
42
|
+
- lib/fixjour/redundant_check.rb
|
43
|
+
- lib/fixjour/verify.rb
|
42
44
|
- lib/fixjour.rb
|
43
45
|
has_rdoc: true
|
44
46
|
homepage: http://github.com/nakajima/fixjour
|