factory_girl_upgrader 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -0
- data/Gemfile.lock +49 -0
- data/LICENSE +20 -0
- data/README.rdoc +62 -0
- data/lib/factory_girl/upgrader/runner.rb +26 -0
- data/lib/factory_girl/upgrader/transformer.rb +88 -0
- data/lib/factory_girl/upgrader/version.rb +5 -0
- data/lib/factory_girl/upgrader.rb +11 -0
- data/spec/factory_girl/upgrader/transformer_spec.rb +28 -0
- data/spec/matchers/should_transform_to.rb +26 -0
- data/spec/spec_helper.rb +10 -0
- metadata +144 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
factory_girl_upgrader (0.1.0)
|
5
|
+
activesupport (~> 3.0.10)
|
6
|
+
factory_girl (~> 2.0)
|
7
|
+
i18n (~> 0.6.0)
|
8
|
+
ruby_parser (~> 2.3.1)
|
9
|
+
ruby_scribe (~> 0.1.0)
|
10
|
+
ruby_transform (~> 0.1.0)
|
11
|
+
thor (~> 0.13)
|
12
|
+
|
13
|
+
GEM
|
14
|
+
remote: http://rubygems.org/
|
15
|
+
specs:
|
16
|
+
activesupport (3.0.10)
|
17
|
+
diff-lcs (1.1.3)
|
18
|
+
factory_girl (2.1.0)
|
19
|
+
i18n (0.6.0)
|
20
|
+
rspec (2.6.0)
|
21
|
+
rspec-core (~> 2.6.0)
|
22
|
+
rspec-expectations (~> 2.6.0)
|
23
|
+
rspec-mocks (~> 2.6.0)
|
24
|
+
rspec-core (2.6.4)
|
25
|
+
rspec-expectations (2.6.0)
|
26
|
+
diff-lcs (~> 1.1.2)
|
27
|
+
rspec-mocks (2.6.0)
|
28
|
+
ruby_parser (2.3.1)
|
29
|
+
sexp_processor (~> 3.0)
|
30
|
+
ruby_scribe (0.1.2)
|
31
|
+
activesupport (~> 3.0.10)
|
32
|
+
i18n (~> 0.6.0)
|
33
|
+
ruby_parser (~> 2.3.1)
|
34
|
+
thor (~> 0.13)
|
35
|
+
ruby_transform (0.1.1)
|
36
|
+
activesupport (~> 3.0.10)
|
37
|
+
i18n (~> 0.6.0)
|
38
|
+
ruby_parser (~> 2.3.1)
|
39
|
+
ruby_scribe (~> 0.1.0)
|
40
|
+
thor (~> 0.13)
|
41
|
+
sexp_processor (3.0.7)
|
42
|
+
thor (0.14.6)
|
43
|
+
|
44
|
+
PLATFORMS
|
45
|
+
ruby
|
46
|
+
|
47
|
+
DEPENDENCIES
|
48
|
+
factory_girl_upgrader!
|
49
|
+
rspec (~> 2.0)
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Ben Hughes
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
= Factory Girl Upgrader
|
2
|
+
|
3
|
+
Uses ruby_parser and ruby_scribe to dynamically convert factory_girl factories in the V1 DSL into the V2 DSL.
|
4
|
+
|
5
|
+
== In-Progress
|
6
|
+
|
7
|
+
NOTE: This gem is not essentially unusable and is being continually worked on - more of a proof of concept for now.
|
8
|
+
|
9
|
+
== Command-Line Usage
|
10
|
+
|
11
|
+
The gem comes with a thor task that you can use to print out a converted version of any Ruby file containing factory_girl V1 code:
|
12
|
+
|
13
|
+
$ factory_girl_upgrader cat test_project.rb
|
14
|
+
|
15
|
+
== API Usage
|
16
|
+
|
17
|
+
This is built on the tree-walking base class RubyTransform::Transformer from the +ruby_transform+ project.
|
18
|
+
The principal transform, which is a composite of other more granular transforms, is +RSpecify::Transformer+.
|
19
|
+
Here's how it can be used in conjunction with +ruby_parser+:
|
20
|
+
|
21
|
+
sexp = RubyParser.new.parse(File.read(path))
|
22
|
+
sexp = FactoryGirl::Upgrader::Transformer.new.transform(sexp)
|
23
|
+
|
24
|
+
emitter = RubyScribe::Emitter.new
|
25
|
+
emitter.methods_without_parenthesis += ["factory"]
|
26
|
+
emitter.emit(sexp)
|
27
|
+
|
28
|
+
== Supported factory_girl V1 features:
|
29
|
+
|
30
|
+
* Simple attribute setting
|
31
|
+
* Sequences with a block
|
32
|
+
* Associations (without options)
|
33
|
+
|
34
|
+
NOTE: Indeed, this is only the basics. This will be expanded in the future to be a more comprehensive set of transformations.
|
35
|
+
|
36
|
+
== Limitations
|
37
|
+
|
38
|
+
To make this more DSL-friendly without parentheses requires expansion of the emitter configuration on ruby_scribe
|
39
|
+
(we need to be able to give ruby_scribe AST node hints on parentheses and block style).
|
40
|
+
|
41
|
+
== Example:
|
42
|
+
|
43
|
+
=== Original (factory_girl V1):
|
44
|
+
|
45
|
+
Factory.define(:product) do |f|
|
46
|
+
f.association :category
|
47
|
+
f.sequence(:name) {|n| "Product #{n}" }
|
48
|
+
f.price 19.95
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
=== Transformed (factory_girl V2):
|
53
|
+
|
54
|
+
FactoryGirl.define do
|
55
|
+
factory :product do
|
56
|
+
category
|
57
|
+
price(19.95)
|
58
|
+
sequence(:name) do |n|
|
59
|
+
"Product #{n}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "factory_girl/upgrader"
|
3
|
+
|
4
|
+
module FactoryGirl
|
5
|
+
module Upgrader
|
6
|
+
class Runner < Thor
|
7
|
+
desc :cat, "Takes a single ruby file, parses it, and outputs the scribed version."
|
8
|
+
def cat(path)
|
9
|
+
sexp = RubyParser.new.parse(File.read(path))
|
10
|
+
sexp = FactoryGirl::Upgrader::Transformer.new.transform(sexp)
|
11
|
+
RubyScribe::Emitter.new.tap do |emitter|
|
12
|
+
emitter.methods_without_parenthesis += ["factory"]
|
13
|
+
puts emitter.emit(sexp)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def expand_paths(paths = [])
|
20
|
+
paths.map do |path|
|
21
|
+
[path] + Dir[path + "**/*.rb"]
|
22
|
+
end.flatten.uniq.reject {|f| File.directory?(f) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module FactoryGirl
|
2
|
+
module Upgrader
|
3
|
+
class Transformer < RubyTransform::Transformer
|
4
|
+
def transform(e)
|
5
|
+
super(transform_factories(e))
|
6
|
+
end
|
7
|
+
|
8
|
+
def transform_factories(e)
|
9
|
+
if matches_define_factory?(e)
|
10
|
+
transform_factory_definition(e)
|
11
|
+
else
|
12
|
+
e
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def matches_define_factory?(e)
|
17
|
+
e.is_a?(Sexp) && e.kind == :iter && # We're in a block
|
18
|
+
e.body.first.is_a?(Sexp) && e.body.first.kind == :call && # What's calling
|
19
|
+
e.body.first.body.first == s(:const, :Factory) && e.body.first.body.second == :define && # Factory.define
|
20
|
+
e.body.second.try(:kind) == :lasgn && # and we're passing a block variable for the factory
|
21
|
+
e.body.third.try(:kind) == :block # and we have a block
|
22
|
+
end
|
23
|
+
|
24
|
+
def transform_factory_definition(e)
|
25
|
+
factory_name = e.body.first.body.third.body.first.body.first # Yeah... we really need an OO AST model.
|
26
|
+
local_variable = e.body.second.body.first
|
27
|
+
block = e.body.third
|
28
|
+
|
29
|
+
s(:iter,
|
30
|
+
s(:call, s(:const, :FactoryGirl), :define, s(:arglist)), nil,
|
31
|
+
s(:iter,
|
32
|
+
s(:call, nil, :factory, s(:arglist, s(:lit, factory_name.to_sym))), nil,
|
33
|
+
transform_factory_definition_block(block, local_variable)
|
34
|
+
)
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def transform_factory_definition_block(block, local_variable)
|
39
|
+
Sexp.new(*([:block] + block.body.map {|e|
|
40
|
+
case
|
41
|
+
when matches_factory_association?(e, local_variable)
|
42
|
+
transform_factory_association(e)
|
43
|
+
when matches_factory_sequence?(e, local_variable)
|
44
|
+
transform_factory_sequence(e)
|
45
|
+
when matches_factory_attribute?(e, local_variable)
|
46
|
+
transform_factory_attribute(e)
|
47
|
+
else
|
48
|
+
e
|
49
|
+
end
|
50
|
+
}))
|
51
|
+
end
|
52
|
+
|
53
|
+
# Factory Attributes:
|
54
|
+
def matches_factory_attribute?(e, local_variable)
|
55
|
+
e.is_a?(Sexp) && e.kind == :call && e.body.first.kind == :lvar && e.body.first.body.first == local_variable.to_sym
|
56
|
+
end
|
57
|
+
|
58
|
+
def transform_factory_attribute(e)
|
59
|
+
e.dup.tap do |sexp|
|
60
|
+
sexp[1] = nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Factory Sequences:
|
65
|
+
def matches_factory_sequence?(e, local_variable)
|
66
|
+
e.is_a?(Sexp) && e.kind == :iter && matches_factory_attribute?(e.body.first, local_variable)
|
67
|
+
end
|
68
|
+
|
69
|
+
def transform_factory_sequence(e)
|
70
|
+
e.dup.tap do |sexp|
|
71
|
+
sexp[1] = transform_factory_attribute(sexp[1])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Factory Associations:
|
76
|
+
def matches_factory_association?(e, local_variable)
|
77
|
+
e.is_a?(Sexp) && e.kind == :call && e.body.first.kind == :lvar && e.body.first.body.first == local_variable.to_sym &&
|
78
|
+
e.body.second == :association
|
79
|
+
end
|
80
|
+
|
81
|
+
def transform_factory_association(e)
|
82
|
+
association_name = e.body.third.body.first.body.first
|
83
|
+
|
84
|
+
s(:call, nil, association_name, s(:arglist))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "factory_girl"
|
3
|
+
require "ruby_parser"
|
4
|
+
require "ruby_scribe"
|
5
|
+
require "ruby_transform"
|
6
|
+
|
7
|
+
require "factory_girl/upgrader/transformer"
|
8
|
+
|
9
|
+
Dir[File.join(File.dirname(__FILE__), "upgrader/transformers/**/*.rb")].each do |file|
|
10
|
+
require file
|
11
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe FactoryGirl::Upgrader::Transformer do
|
4
|
+
|
5
|
+
describe "old factory_girl V1 factory" do
|
6
|
+
subject { '
|
7
|
+
Factory.define(:product) do |f|
|
8
|
+
f.association :category
|
9
|
+
f.price 19.95
|
10
|
+
f.sequence(:name) {|n| "Product #{n}" }
|
11
|
+
end
|
12
|
+
' }
|
13
|
+
|
14
|
+
it { should transform_to("new factory_girl V2 factory", '
|
15
|
+
FactoryGirl.define do
|
16
|
+
factory(:product) do
|
17
|
+
category
|
18
|
+
price(19.95)
|
19
|
+
|
20
|
+
sequence(:name) do |n|
|
21
|
+
"Product #{n}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
') }
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
RSpec::Matchers.define :transform_to do |desc, expected|
|
2
|
+
match do |actual|
|
3
|
+
actual_as_sexp = actual.is_a?(String) ? RubyParser.new.parse(actual) : actual
|
4
|
+
expected_as_sexp = expected.is_a?(String) ? RubyParser.new.parse(expected) : expected
|
5
|
+
|
6
|
+
transformer = described_class.is_a?(Class) ? described_class.new : described_class
|
7
|
+
@transformed = transformer.transform(actual_as_sexp)
|
8
|
+
@transformed == expected_as_sexp
|
9
|
+
end
|
10
|
+
|
11
|
+
failure_message_for_should do |actual|
|
12
|
+
"expected that:\n\n#{RubyParser.new.parse(actual)}\n\nwould transform to:\n\n#{RubyParser.new.parse(expected)}\n\nbut instead was:\n\n#{@transformed}\n\n#{transformed_as_ruby}"
|
13
|
+
end
|
14
|
+
|
15
|
+
failure_message_for_should_not do |actual|
|
16
|
+
"expected that:\n\n#{RubyParser.new.parse(actual)}\n\nwould not transform to:\n\n#{RubyParser.new.parse(expected)}\n\nbut instead was:\n\n#{@transformed}\n\n#{transformed_as_ruby}"
|
17
|
+
end
|
18
|
+
|
19
|
+
description do
|
20
|
+
"transform with to #{desc}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def transformed_as_ruby
|
24
|
+
RubyScribe::Emitter.new.emit(@transformed) rescue nil
|
25
|
+
end
|
26
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), "../lib"))
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "rspec"
|
5
|
+
require "factory_girl/upgrader"
|
6
|
+
|
7
|
+
# Requires supporting files with custom matchers and macros, etc,
|
8
|
+
# in ./support/ and its subdirectories.
|
9
|
+
Dir["#{File.dirname(__FILE__)}/matchers/**/*.rb"].each {|f| require f}
|
10
|
+
|
metadata
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: factory_girl_upgrader
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ben Hughes
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-11 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: &70286276079920 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0.13'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70286276079920
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
requirement: &70286276078840 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.0.10
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70286276078840
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: i18n
|
38
|
+
requirement: &70286276078100 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.6.0
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70286276078100
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: factory_girl
|
49
|
+
requirement: &70286276077420 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70286276077420
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: ruby_parser
|
60
|
+
requirement: &70286276076940 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 2.3.1
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70286276076940
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ruby_scribe
|
71
|
+
requirement: &70286276076340 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 0.1.0
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70286276076340
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: ruby_transform
|
82
|
+
requirement: &70286276075560 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 0.1.0
|
88
|
+
type: :runtime
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70286276075560
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: rspec
|
93
|
+
requirement: &70286276074860 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ~>
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '2.0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *70286276074860
|
102
|
+
description: Uses ruby_parser and ruby_scribe to dynamically convert factory_girl
|
103
|
+
factories in the V1 DSL into the V2 DSL.
|
104
|
+
email: ben@railsgarden.com
|
105
|
+
executables: []
|
106
|
+
extensions: []
|
107
|
+
extra_rdoc_files: []
|
108
|
+
files:
|
109
|
+
- lib/factory_girl/upgrader/runner.rb
|
110
|
+
- lib/factory_girl/upgrader/transformer.rb
|
111
|
+
- lib/factory_girl/upgrader/version.rb
|
112
|
+
- lib/factory_girl/upgrader.rb
|
113
|
+
- spec/factory_girl/upgrader/transformer_spec.rb
|
114
|
+
- spec/matchers/should_transform_to.rb
|
115
|
+
- spec/spec_helper.rb
|
116
|
+
- Gemfile
|
117
|
+
- Gemfile.lock
|
118
|
+
- LICENSE
|
119
|
+
- README.rdoc
|
120
|
+
homepage: http://github.com/rubiety/factory_girl_upgrader
|
121
|
+
licenses: []
|
122
|
+
post_install_message:
|
123
|
+
rdoc_options: []
|
124
|
+
require_paths:
|
125
|
+
- lib
|
126
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ! '>='
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: 1.3.4
|
138
|
+
requirements: []
|
139
|
+
rubyforge_project: factory_girl_upgrader
|
140
|
+
rubygems_version: 1.8.10
|
141
|
+
signing_key:
|
142
|
+
specification_version: 3
|
143
|
+
summary: Converts factory_girl V1 DSL factories to factory_girl V2 DSL.
|
144
|
+
test_files: []
|