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 ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
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,5 @@
1
+ module FactoryGirl
2
+ module Upgrader
3
+ VERSION = "0.1.0"
4
+ end
5
+ 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
@@ -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: []