usine 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/README.md +64 -43
- data/lib/usine.rb +11 -52
- data/lib/usine/null_model.rb +3 -0
- data/lib/usine/operation_factory.rb +31 -0
- data/lib/usine/operation_wrapper.rb +49 -0
- data/lib/usine/version.rb +1 -1
- data/usine.gemspec +1 -0
- metadata +18 -7
- data/lib/usine/definition.rb +0 -11
- data/lib/usine/definition_evaluator.rb +0 -39
- data/lib/usine/exceptions.rb +0 -11
- data/lib/usine/factory.rb +0 -13
- data/lib/usine/factory_evaluator.rb +0 -73
- data/lib/usine/sequence.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03d1e6d91e2856f9104d7a7c7b6907988674cdf8
|
4
|
+
data.tar.gz: 7573d835285b97a7243304ab437bd43ae425e150
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fcc0c03dff27f57b4a1d63eda0c11803ee7bb8fee770b8eb9fa2378fe0851b65fa6eddee7003741d89a8a15351b49585fe1ba013603e9332eb26387fc4537028
|
7
|
+
data.tar.gz: df77515eb45fe2bec61f553fa20c7e696beb544ca93a753895bbf28f4772bd17fec5fa7ae59219d03d30e710648017ca0480eef1343dc3288705e2a73f21436e
|
data/README.md
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
# Usine
|
2
2
|
|
3
|
-
Usine (french word for factory) is a
|
4
|
-
when using Trailblazer’s operations. [Trailblazer](http://trailblazer.to/) advocates against using factory_girl to avoid
|
5
|
-
differences when initializing objects. Usine follows this path but allows you to define defaults for the
|
6
|
-
parameters passed to your operations.
|
3
|
+
Usine (french word for factory) is a wrapper around factory_girls with two goals: simplify using [Trailblazer](http://trailblazer.to/) with factory_girl, and avoid initializing models through factory_girl instead of Trailblazer.
|
7
4
|
|
8
5
|
## Installation
|
9
6
|
|
@@ -23,72 +20,96 @@ Or install it yourself as:
|
|
23
20
|
|
24
21
|
## Usage
|
25
22
|
|
26
|
-
|
27
|
-
|
28
|
-
Definitions are the base of anything in Usine, they are used in factories to generate
|
29
|
-
the hash of params sent to the operation.
|
23
|
+
Usine let you reuse your factories and use them to define the params sent to your Operation.
|
30
24
|
|
31
25
|
```ruby
|
32
|
-
|
33
|
-
|
26
|
+
FactoryGirl.define do
|
27
|
+
factory :item do
|
28
|
+
title { "Default title"}
|
29
|
+
end
|
30
|
+
|
31
|
+
factory :user do
|
32
|
+
email { "xx@exxample.com"}
|
33
|
+
end
|
34
34
|
end
|
35
35
|
|
36
|
-
Usine
|
37
|
-
|
36
|
+
# If no symbol given, Usine will try to find an existing factory with this name
|
37
|
+
Usine.operation(Item::Create) do
|
38
|
+
item
|
39
|
+
current_user :user
|
38
40
|
end
|
39
|
-
```
|
40
41
|
|
41
|
-
|
42
|
+
# Usine will transmit [call, run, present] to the operation invocation
|
43
|
+
# so you can have the kind of operation you want in your test
|
44
|
+
# for example `present` will not run process in your Operation
|
45
|
+
Usine.(Item::Create, item: {title: "Another title"})
|
46
|
+
Usine.call(Item::Create, item: {title: "Another title"})
|
47
|
+
Usine.run(Item::Create, item: {title: "Another title"})
|
48
|
+
Usine.present(Item::Create, item: {title: "Another title"})
|
49
|
+
```
|
42
50
|
|
43
|
-
|
44
|
-
This is what you will call when building your objects in a test.
|
51
|
+
### Model less factories
|
45
52
|
|
53
|
+
If your params are not related to a model you can simply create a factory this way:
|
46
54
|
```ruby
|
47
|
-
|
48
|
-
|
49
|
-
|
55
|
+
FactoryGirl.define do
|
56
|
+
factory :search, class:Usine::NullModel do
|
57
|
+
query { "*"}
|
58
|
+
end
|
50
59
|
end
|
51
60
|
```
|
52
61
|
|
53
|
-
###
|
62
|
+
### Factory girl features
|
54
63
|
|
55
|
-
|
56
|
-
Which means you have 3 different ways to invoke a factory :
|
64
|
+
All factory_girl features should work, sequences for example are working:
|
57
65
|
|
58
66
|
```ruby
|
59
|
-
|
60
|
-
|
61
|
-
|
67
|
+
FactoryGirl.define do
|
68
|
+
sequence(:email) do |n|
|
69
|
+
"some_email_#{n}@example.com"
|
70
|
+
end
|
71
|
+
|
72
|
+
factory :user do
|
73
|
+
contact { generate(:email) }
|
74
|
+
end
|
75
|
+
end
|
62
76
|
```
|
63
77
|
|
64
|
-
|
78
|
+
### Writing a test with Usine
|
65
79
|
|
66
|
-
Let see an example in a test :
|
67
80
|
```
|
68
|
-
|
69
|
-
|
81
|
+
# Without Usine
|
82
|
+
let(:item) {
|
83
|
+
Item::Create.({
|
84
|
+
item: {
|
85
|
+
title: "DEFAULT_TITLE"
|
86
|
+
},
|
87
|
+
current_user: User::Create.(email: "some_email@example.com").model
|
88
|
+
}).model
|
70
89
|
}
|
71
|
-
```
|
72
90
|
|
73
|
-
|
91
|
+
# With Usine
|
92
|
+
FactoryGirl.define do
|
93
|
+
factory :item do
|
94
|
+
title { "DEFAULT_TITLE" }
|
95
|
+
end
|
74
96
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
# global sequence
|
79
|
-
Usine.sequence(:title) do |n|
|
80
|
-
"title number #{n}"
|
97
|
+
factory :user do
|
98
|
+
email { "some_email@example.com" }
|
99
|
+
end
|
81
100
|
end
|
82
101
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
email # if no block given, Usine will try to invoke generate(:email)
|
87
|
-
title # and will also search in global sequences
|
88
|
-
alt_email { generate(:email) }
|
102
|
+
Usine.operation(Item::Create) do
|
103
|
+
item
|
104
|
+
current_user :user
|
89
105
|
end
|
106
|
+
|
107
|
+
let(:item) { Usine.(Item::Create).model }
|
90
108
|
```
|
91
109
|
|
110
|
+
The second example might look more verbose, but you only have to define factories/operations one time.
|
111
|
+
And then you can reuse it for all your tests.
|
112
|
+
|
92
113
|
## Contributing
|
93
114
|
|
94
115
|
Bug reports and pull requests are welcome on GitHub at https://github.com/jjaffeux/usine. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
data/lib/usine.rb
CHANGED
@@ -1,68 +1,27 @@
|
|
1
|
+
require "uber/inheritable_attr"
|
2
|
+
require "factory_girl"
|
1
3
|
require "usine/version"
|
2
4
|
require "usine/utils"
|
3
|
-
require "usine/
|
4
|
-
require "usine/
|
5
|
-
require "usine/
|
6
|
-
require "usine/definition_evaluator"
|
7
|
-
require "usine/definition"
|
8
|
-
require "usine/sequence"
|
9
|
-
require "uber/inheritable_attr"
|
5
|
+
require "usine/null_model"
|
6
|
+
require "usine/operation_factory"
|
7
|
+
require "usine/operation_wrapper"
|
10
8
|
|
11
9
|
module Usine
|
12
10
|
extend Uber::InheritableAttr
|
13
|
-
inheritable_attr :
|
14
|
-
self.
|
15
|
-
inheritable_attr :factories
|
16
|
-
self.factories = []
|
17
|
-
inheritable_attr :sequences
|
18
|
-
self.sequences = []
|
11
|
+
inheritable_attr :operations
|
12
|
+
self.operations = []
|
19
13
|
|
20
14
|
class << self
|
21
|
-
|
22
15
|
[:call, :run, :present].each do |mode|
|
23
16
|
define_method mode, ->(*args, &block) {
|
24
17
|
operation = args.shift
|
25
|
-
|
26
|
-
|
18
|
+
attributes = args.shift || {}
|
19
|
+
OperationWrapper.(mode, operation, attributes)
|
27
20
|
}
|
28
21
|
end
|
29
22
|
|
30
|
-
def
|
31
|
-
self.
|
32
|
-
|
33
|
-
self.factories << Factory.new(operation, *extensions, &block)
|
34
|
-
|
35
|
-
extensions.each do |extension|
|
36
|
-
self.factories << Factory.new(operation, *extension, &block)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def sequence(name, initial_value = 1, &block)
|
41
|
-
self.sequences << Sequence.new(name, initial_value, &block)
|
42
|
-
end
|
43
|
-
|
44
|
-
def definition(attribute, *extensions, &block)
|
45
|
-
self.definitions ||= []
|
46
|
-
|
47
|
-
self.definitions << Definition.new(attribute, &block)
|
48
|
-
|
49
|
-
extensions.each do |extension|
|
50
|
-
self.definitions << Definition.new(attribute, &block)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
protected
|
55
|
-
|
56
|
-
def find_factory_for_operation(operation)
|
57
|
-
factory = Usine.factories.detect do |f|
|
58
|
-
f.operation == operation
|
59
|
-
end
|
60
|
-
|
61
|
-
if factory.nil?
|
62
|
-
raise "NOT FOUND FACTORY for #{operation}"
|
63
|
-
end
|
64
|
-
|
65
|
-
factory
|
23
|
+
def operation(operation, *args, &block)
|
24
|
+
self.operations << OperationFactory.new(operation, &block)
|
66
25
|
end
|
67
26
|
end
|
68
27
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Usine
|
2
|
+
class OperationFactory
|
3
|
+
attr_reader :operation_class
|
4
|
+
|
5
|
+
def initialize(operation_class, &block)
|
6
|
+
@operation_class = operation_class
|
7
|
+
@block = block
|
8
|
+
@attributes = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def process
|
12
|
+
self.instance_eval(&@block)
|
13
|
+
@attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(method_symbol, factory_name = nil, &block)
|
17
|
+
if factory_name
|
18
|
+
@attributes[method_symbol] = attributes_for_factory_name(factory_name)
|
19
|
+
else
|
20
|
+
@attributes[method_symbol] = attributes_for_factory_name(method_symbol)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def attributes_for_factory_name(name)
|
27
|
+
factory = FactoryGirl.factory_by_name(name)
|
28
|
+
factory.run(FactoryGirl::Strategy::AttributesFor, {})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Usine
|
2
|
+
class OperationWrapper
|
3
|
+
def initialize(mode, operation, attributes = {})
|
4
|
+
@mode = mode
|
5
|
+
@operation = operation
|
6
|
+
@operation_factory = find_operation_factory(operation)
|
7
|
+
@attributes = attributes
|
8
|
+
end
|
9
|
+
|
10
|
+
def operations=(operations)
|
11
|
+
@operations = operations
|
12
|
+
end
|
13
|
+
|
14
|
+
def operations
|
15
|
+
@operations ||= Usine.operations
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.call(mode, operation, attributes = {})
|
19
|
+
wrapper = new(mode, operation, attributes)
|
20
|
+
wrapper.process
|
21
|
+
end
|
22
|
+
|
23
|
+
def process
|
24
|
+
factory_attributes = @operation_factory.process
|
25
|
+
merged_attributes = Utils.merge_hashes(factory_attributes, @attributes)
|
26
|
+
@operation.send(@mode, merged_attributes)
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def find_operation_factory(operation_class)
|
32
|
+
operation_factory = operations.detect do |op|
|
33
|
+
op.operation_class == operation_class
|
34
|
+
end
|
35
|
+
|
36
|
+
unless operation_factory
|
37
|
+
message = <<-MSG
|
38
|
+
Couldn’t find an operation factory for: #{operation_class}
|
39
|
+
|
40
|
+
Please define it with:
|
41
|
+
Usine.operation(#{operation_class}) {}
|
42
|
+
MSG
|
43
|
+
raise(ArgumentError, message)
|
44
|
+
end
|
45
|
+
|
46
|
+
operation_factory
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/usine/version.rb
CHANGED
data/usine.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: usine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joffrey JAFFEUX
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: factory_girl
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,12 +112,9 @@ files:
|
|
98
112
|
- bin/console
|
99
113
|
- bin/setup
|
100
114
|
- lib/usine.rb
|
101
|
-
- lib/usine/
|
102
|
-
- lib/usine/
|
103
|
-
- lib/usine/
|
104
|
-
- lib/usine/factory.rb
|
105
|
-
- lib/usine/factory_evaluator.rb
|
106
|
-
- lib/usine/sequence.rb
|
115
|
+
- lib/usine/null_model.rb
|
116
|
+
- lib/usine/operation_factory.rb
|
117
|
+
- lib/usine/operation_wrapper.rb
|
107
118
|
- lib/usine/utils.rb
|
108
119
|
- lib/usine/version.rb
|
109
120
|
- usine.gemspec
|
data/lib/usine/definition.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
module Usine
|
2
|
-
class DefinitionEvaluator
|
3
|
-
attr_reader :attributes
|
4
|
-
attr_reader :sequences
|
5
|
-
attr_reader :scoped_sequences
|
6
|
-
|
7
|
-
def initialize(sequences = [])
|
8
|
-
@sequences = sequences
|
9
|
-
@scoped_sequences = []
|
10
|
-
@attributes = {}
|
11
|
-
end
|
12
|
-
|
13
|
-
def method_missing(method_symbol, *args, &block)
|
14
|
-
if block
|
15
|
-
@attributes[method_symbol] = block.call
|
16
|
-
else
|
17
|
-
@attributes[method_symbol] = generate(method_symbol)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def generate(attribute)
|
22
|
-
if sequence = scoped_sequences.detect { |x| x.attribute == attribute }
|
23
|
-
sequence.next
|
24
|
-
elsif sequence = sequences.detect { |x| x.attribute == attribute }
|
25
|
-
sequence.next
|
26
|
-
else
|
27
|
-
message = <<-MSG
|
28
|
-
Couldn’t find a sequence named: #{attribute}
|
29
|
-
Available sequences: #{scoped_sequences.concat(sequences).map(&:attribute).join(',')}
|
30
|
-
MSG
|
31
|
-
raise(UsineError::SequenceNotFound, message)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def sequence(name, initial_value = 1, &block)
|
36
|
-
@scoped_sequences << Sequence.new(name, initial_value, &block)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
data/lib/usine/exceptions.rb
DELETED
data/lib/usine/factory.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
module Usine
|
2
|
-
class FactoryEvaluator
|
3
|
-
attr_reader :mode
|
4
|
-
attr_reader :attributes
|
5
|
-
attr_reader :generated_attributes
|
6
|
-
attr_reader :factory
|
7
|
-
|
8
|
-
def self.call(factory, mode, attributes = {})
|
9
|
-
factory = new(factory, mode, attributes)
|
10
|
-
factory.process!
|
11
|
-
end
|
12
|
-
|
13
|
-
def definitions=(definitions)
|
14
|
-
@definitions = definitions
|
15
|
-
end
|
16
|
-
|
17
|
-
def definitions
|
18
|
-
@definitions ||= Usine.definitions
|
19
|
-
end
|
20
|
-
|
21
|
-
def sequences=(sequences)
|
22
|
-
@sequences = sequences
|
23
|
-
end
|
24
|
-
|
25
|
-
def sequences
|
26
|
-
@sequences ||= Usine.sequences
|
27
|
-
end
|
28
|
-
|
29
|
-
def initialize(factory, mode, attributes = {})
|
30
|
-
@mode = mode
|
31
|
-
@factory = factory
|
32
|
-
@attributes = attributes
|
33
|
-
@generated_attributes = {}
|
34
|
-
end
|
35
|
-
|
36
|
-
def use(definition_name, *args)
|
37
|
-
definition = definitions.detect do |definition|
|
38
|
-
definition.name == definition_name
|
39
|
-
end
|
40
|
-
|
41
|
-
if definition.nil?
|
42
|
-
message = <<-MSG
|
43
|
-
Couldn’t find a definition named: #{definition_name}
|
44
|
-
Available definitions: #{definitions.map(&:name).join(',')}
|
45
|
-
MSG
|
46
|
-
raise(UsineError::DefinitionNotFound, message)
|
47
|
-
end
|
48
|
-
|
49
|
-
evaluated_definition = DefinitionEvaluator.new(sequences)
|
50
|
-
evaluated_definition.instance_eval(&definition.block)
|
51
|
-
evaluated_definition.attributes
|
52
|
-
end
|
53
|
-
|
54
|
-
def method_missing(method_symbol, *args, &block)
|
55
|
-
if block
|
56
|
-
@generated_attributes[method_symbol] = self.instance_eval(&block)
|
57
|
-
else
|
58
|
-
@generated_attributes[method_symbol] = use(method_symbol, *args)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def process!
|
63
|
-
self.instance_eval(&factory.block)
|
64
|
-
@factory.operation.send(@mode, merged_attributes)
|
65
|
-
end
|
66
|
-
|
67
|
-
protected
|
68
|
-
|
69
|
-
def merged_attributes
|
70
|
-
Utils.merge_hashes(@generated_attributes, @attributes)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
data/lib/usine/sequence.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module Usine
|
2
|
-
class Sequence
|
3
|
-
attr_reader :attribute
|
4
|
-
|
5
|
-
def initialize(attribute, *args, &block)
|
6
|
-
@attribute = attribute
|
7
|
-
@block = block
|
8
|
-
@value = args.first || 1
|
9
|
-
|
10
|
-
unless @value.respond_to?(:next)
|
11
|
-
raise(UsineError::SequenceInvalidInitialValue, "Invalid initial value, it must respond to #next")
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def next
|
16
|
-
@block.call(@value)
|
17
|
-
ensure
|
18
|
-
@value = @value.next
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|