synvert 0.0.17 → 0.1.0

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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -1
  3. data/CHANGELOG.md +4 -0
  4. data/README.md +7 -26
  5. data/bin/synvert +0 -1
  6. data/lib/synvert/cli.rb +26 -14
  7. data/lib/synvert/snippet.rb +17 -0
  8. data/lib/synvert/version.rb +1 -1
  9. data/lib/synvert.rb +3 -11
  10. data/synvert.gemspec +2 -3
  11. metadata +6 -85
  12. data/lib/synvert/configuration.rb +0 -25
  13. data/lib/synvert/exceptions.rb +0 -13
  14. data/lib/synvert/node_ext.rb +0 -319
  15. data/lib/synvert/rewriter/action.rb +0 -224
  16. data/lib/synvert/rewriter/condition.rb +0 -56
  17. data/lib/synvert/rewriter/gem_spec.rb +0 -42
  18. data/lib/synvert/rewriter/instance.rb +0 -185
  19. data/lib/synvert/rewriter/scope.rb +0 -46
  20. data/lib/synvert/rewriter.rb +0 -200
  21. data/lib/synvert/snippets/check_syntax.rb +0 -5
  22. data/lib/synvert/snippets/factory_girl/syntax_methods.rb +0 -98
  23. data/lib/synvert/snippets/rails/convert_dynamic_finders.rb +0 -93
  24. data/lib/synvert/snippets/rails/strong_parameters.rb +0 -93
  25. data/lib/synvert/snippets/rails/upgrade_3_0_to_3_1.rb +0 -135
  26. data/lib/synvert/snippets/rails/upgrade_3_1_to_3_2.rb +0 -42
  27. data/lib/synvert/snippets/rails/upgrade_3_2_to_4_0.rb +0 -230
  28. data/lib/synvert/snippets/rspec/be_close_to_be_within.rb +0 -18
  29. data/lib/synvert/snippets/rspec/block_to_expect.rb +0 -22
  30. data/lib/synvert/snippets/rspec/boolean_matcher.rb +0 -20
  31. data/lib/synvert/snippets/rspec/collection_matcher.rb +0 -34
  32. data/lib/synvert/snippets/rspec/its_to_it.rb +0 -89
  33. data/lib/synvert/snippets/rspec/message_expectation.rb +0 -41
  34. data/lib/synvert/snippets/rspec/method_stub.rb +0 -84
  35. data/lib/synvert/snippets/rspec/negative_error_expectation.rb +0 -21
  36. data/lib/synvert/snippets/rspec/new_syntax.rb +0 -18
  37. data/lib/synvert/snippets/rspec/one_liner_expectation.rb +0 -71
  38. data/lib/synvert/snippets/rspec/should_to_expect.rb +0 -50
  39. data/lib/synvert/snippets/rspec/stub_and_mock_to_double.rb +0 -22
  40. data/lib/synvert/snippets/ruby/new_hash_syntax.rb +0 -21
  41. data/lib/synvert/snippets/ruby/new_lambda_syntax.rb +0 -20
  42. data/spec/spec_helper.rb +0 -26
  43. data/spec/support/parser_helper.rb +0 -5
  44. data/spec/synvert/node_ext_spec.rb +0 -201
  45. data/spec/synvert/rewriter/action_spec.rb +0 -225
  46. data/spec/synvert/rewriter/condition_spec.rb +0 -106
  47. data/spec/synvert/rewriter/gem_spec_spec.rb +0 -52
  48. data/spec/synvert/rewriter/instance_spec.rb +0 -163
  49. data/spec/synvert/rewriter/scope_spec.rb +0 -42
  50. data/spec/synvert/rewriter_spec.rb +0 -153
  51. data/spec/synvert/snippets/factory_girl/syntax_methods_spec.rb +0 -154
  52. data/spec/synvert/snippets/rails/convert_dynamic_finders_spec.rb +0 -83
  53. data/spec/synvert/snippets/rails/strong_parameters_spec.rb +0 -132
  54. data/spec/synvert/snippets/rails/upgrade_3_0_to_3_1_spec.rb +0 -88
  55. data/spec/synvert/snippets/rails/upgrade_3_1_to_3_2_spec.rb +0 -41
  56. data/spec/synvert/snippets/rails/upgrade_3_2_to_4_0_spec.rb +0 -299
  57. data/spec/synvert/snippets/rspec/new_syntax_spec.rb +0 -183
  58. data/spec/synvert/snippets/ruby/new_hash_syntax_spec.rb +0 -27
  59. data/spec/synvert/snippets/ruby/new_lambda_syntax_spec.rb +0 -27
@@ -1,185 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Synvert
4
- # Instance is an execution unit, it finds specified ast nodes,
5
- # checks if the nodes match some conditions, then add, replace or remove code.
6
- #
7
- # One instance can contains one or many [Synvert::Rewriter::Scope] and [Synvert::Rewriter::Condition].
8
- class Rewriter::Instance
9
- # @!attribute [rw] current_node
10
- # @return current parsing node
11
- # @!attribute [rw] current_source
12
- # @return current source code of file
13
- # @!attribute [rw] current_file
14
- # @return current filename
15
- attr_accessor :current_node, :current_source, :current_file
16
-
17
- # Initialize an instance.
18
- #
19
- # @param file_pattern [String] pattern to find files, e.g. spec/**/*_spec.rb
20
- # @param block [Block] block code to find nodes, match conditions and rewrite code.
21
- # @return [Synvert::Rewriter::Instance]
22
- def initialize(file_pattern, &block)
23
- @actions = []
24
- @file_pattern = file_pattern
25
- @block = block
26
- end
27
-
28
- # Process the instance.
29
- # It finds all files, for each file, it executes the block code, gets all rewrite actions,
30
- # and rewrite source code back to original file.
31
- def process
32
- parser = Parser::CurrentRuby.new
33
- file_pattern = File.join(Configuration.instance.get(:path), @file_pattern)
34
- Dir.glob(file_pattern).each do |file_path|
35
- unless Configuration.instance.get(:skip_files).include? file_path
36
- begin
37
- source = File.read(file_path)
38
- buffer = Parser::Source::Buffer.new file_path
39
- buffer.source = source
40
-
41
- parser.reset
42
- ast = parser.parse buffer
43
-
44
- @current_file = file_path
45
- @current_source = source
46
- @current_node = ast
47
- instance_eval &@block
48
- @current_node = ast
49
-
50
- @actions.sort!
51
- check_conflict_actions
52
- @actions.reverse.each do |action|
53
- source[action.begin_pos...action.end_pos] = action.rewritten_code
54
- source = remove_code_or_whole_line(source, action.line)
55
- end
56
- @actions = []
57
-
58
- File.write file_path, source
59
- end while !@conflict_actions.empty?
60
- end
61
- end
62
- end
63
-
64
- # Gets current node, it allows to get current node in block code.
65
- #
66
- # @return [Parser::AST::Node]
67
- def node
68
- @current_node
69
- end
70
-
71
- #######
72
- # DSL #
73
- #######
74
-
75
- # Parse within_node dsl, it creates a [Synvert::Rewriter::Scope] to find matching ast nodes,
76
- # then continue operating on each matching ast node.
77
- #
78
- # @param rules [Hash] rules to find mathing ast nodes.
79
- # @param block [Block] block code to continue operating on the matching nodes.
80
- def within_node(rules, &block)
81
- Rewriter::Scope.new(self, rules, &block).process
82
- end
83
-
84
- alias with_node within_node
85
-
86
- # Parse if_exist_node dsl, it creates a [Synvert::Rewriter::IfExistCondition] to check
87
- # if matching nodes exist in the child nodes, if so, then continue operating on each matching ast node.
88
- #
89
- # @param rules [Hash] rules to check mathing ast nodes.
90
- # @param block [Block] block code to continue operating on the matching nodes.
91
- def if_exist_node(rules, &block)
92
- Rewriter::IfExistCondition.new(self, rules, &block).process
93
- end
94
-
95
- # Parse unless_exist_node dsl, it creates a [Synvert::Rewriter::UnlessExistCondition] to check
96
- # if matching nodes doesn't exist in the child nodes, if so, then continue operating on each matching ast node.
97
- #
98
- # @param rules [Hash] rules to check mathing ast nodes.
99
- # @param block [Block] block code to continue operating on the matching nodes.
100
- def unless_exist_node(rules, &block)
101
- Rewriter::UnlessExistCondition.new(self, rules, &block).process
102
- end
103
-
104
- # Parse if_only_exist_node dsl, it creates a [Synvert::Rewriter::IfOnlyExistCondition] to check
105
- # if current node has only one child node and the child node matches rules,
106
- # if so, then continue operating on each matching ast node.
107
- #
108
- # @param rules [Hash] rules to check mathing ast nodes.
109
- # @param block [Block] block code to continue operating on the matching nodes.
110
- def if_only_exist_node(rules, &block)
111
- Rewriter::IfOnlyExistCondition.new(self, rules, &block).process
112
- end
113
-
114
- # Parse append dsl, it creates a [Synvert::Rewriter::AppendAction] to
115
- # append the code to the bottom of current node body.
116
- #
117
- # @param code [String] code need to be appended.
118
- def append(code)
119
- @actions << Rewriter::AppendAction.new(self, code)
120
- end
121
-
122
- # Parse insert dsl, it creates a [Synvert::Rewriter::InsertAction] to
123
- # insert the code to the top of current node body.
124
- #
125
- # @param code [String] code need to be inserted.
126
- def insert(code)
127
- @actions << Rewriter::InsertAction.new(self, code)
128
- end
129
-
130
- # Parse insert_after dsl, it creates a [Synvert::Rewriter::InsertAfterAction] to
131
- # insert the code next to the current node.
132
- #
133
- # @param code [String] code need to be inserted.
134
- def insert_after(node)
135
- @actions << Rewriter::InsertAfterAction.new(self, node)
136
- end
137
-
138
- # Parse replace_with dsl, it creates a [Synvert::Rewriter::ReplaceWithAction] to
139
- # replace current node with code.
140
- #
141
- # @param code [String] code need to be replaced with.
142
- def replace_with(code)
143
- @actions << Rewriter::ReplaceWithAction.new(self, code)
144
- end
145
-
146
- # Parse remove dsl, it creates a [Synvert::Rewriter::RemoveAction] to current node.
147
- def remove
148
- @actions << Rewriter::RemoveAction.new(self)
149
- end
150
-
151
- private
152
-
153
- # It changes source code from bottom to top, and it can change source code twice at the same time.
154
- # So if there is an overlap between two actions, it removes the conflict actions and operate them in the next loop.
155
- def check_conflict_actions
156
- i = @actions.length - 1
157
- @conflict_actions = []
158
- while i > 0
159
- if @actions[i].begin_pos <= @actions[i - 1].end_pos
160
- @conflict_actions << @actions.delete_at(i)
161
- end
162
- i -= 1
163
- end
164
- @conflict_actions
165
- end
166
-
167
- # It checks if code is removed and that line is empty.
168
- #
169
- # @param source [String] source code of file
170
- # @param line [String] the line number
171
- def remove_code_or_whole_line(source, line)
172
- newline_at_end_of_line = source[-1] == "\n"
173
- source_arr = source.split("\n")
174
- if source_arr[line - 1] && source_arr[line - 1].strip.empty?
175
- source_arr.delete_at(line - 1)
176
- if source_arr[line - 2] && source_arr[line - 2].strip.empty? && source_arr[line - 1] && source_arr[line - 1].strip.empty?
177
- source_arr.delete_at(line - 1)
178
- end
179
- source_arr.join("\n") + (newline_at_end_of_line ? "\n" : '')
180
- else
181
- source
182
- end
183
- end
184
- end
185
- end
@@ -1,46 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Synvert
4
- # Scope finds the child nodes which match rules.
5
- class Rewriter::Scope
6
- # Initialize a scope
7
- #
8
- # @param instance [Synvert::Rewriter::Instance]
9
- # @param rules [Hash]
10
- # @param block [Block]
11
- def initialize(instance, rules, &block)
12
- @instance = instance
13
- @rules = rules
14
- @block = block
15
- end
16
-
17
- # Find the matching nodes. It checks the current node and iterates all child nodes,
18
- # then run the block code for each matching node.
19
- def process
20
- current_node = @instance.current_node
21
- return unless current_node
22
- process_with_node current_node do
23
- matching_nodes = []
24
- matching_nodes << current_node if current_node.match? @instance, @rules
25
- current_node.recursive_children do |child_node|
26
- matching_nodes << child_node if child_node.match? @instance, @rules
27
- end
28
- matching_nodes.each do |matching_node|
29
- process_with_node matching_node do
30
- @instance.instance_eval &@block
31
- end
32
- end
33
- end
34
- end
35
-
36
- private
37
-
38
- # Set instance current node properly and process.
39
- # @param node [Parser::AST::Node]
40
- def process_with_node(node)
41
- @instance.current_node = node
42
- yield
43
- @instance.current_node = node
44
- end
45
- end
46
- end
@@ -1,200 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Synvert
4
- # Rewriter is the top level namespace in a snippet.
5
- #
6
- # One Rewriter can contain one or many [Synvert::Rewriter::Instance],
7
- # which define the behavior what files and what codes to detect and rewrite to what code.
8
- #
9
- # Synvert::Rewriter.new 'factory_girl_short_syntax', 'use FactoryGirl short syntax' do
10
- # if_gem 'factory_girl', {gte: '2.0.0'}
11
- #
12
- # within_files 'spec/**/*.rb' do
13
- # with_node type: 'send', receiver: 'FactoryGirl', message: 'create' do
14
- # replace_with "create({{arguments}})"
15
- # end
16
- # end
17
- # end
18
- class Rewriter
19
- autoload :Action, 'synvert/rewriter/action'
20
- autoload :AppendAction, 'synvert/rewriter/action'
21
- autoload :InsertAction, 'synvert/rewriter/action'
22
- autoload :InsertAfterAction, 'synvert/rewriter/action'
23
- autoload :ReplaceWithAction, 'synvert/rewriter/action'
24
- autoload :RemoveAction, 'synvert/rewriter/action'
25
-
26
- autoload :Instance, 'synvert/rewriter/instance'
27
-
28
- autoload :Scope, 'synvert/rewriter/scope'
29
-
30
- autoload :Condition, 'synvert/rewriter/condition'
31
- autoload :IfExistCondition, 'synvert/rewriter/condition'
32
- autoload :UnlessExistCondition, 'synvert/rewriter/condition'
33
- autoload :IfOnlyExistCondition, 'synvert/rewriter/condition'
34
-
35
- autoload :GemSpec, 'synvert/rewriter/gem_spec'
36
-
37
- class <<self
38
- # Register a rewriter with its name.
39
- #
40
- # @param name [String] the unique rewriter name.
41
- # @param rewriter [Synvert::Rewriter] the rewriter to register.
42
- def register(name, rewriter)
43
- @rewriters ||= {}
44
- @rewriters[name] = rewriter
45
- end
46
-
47
- # Fetch a rewriter by name.
48
- #
49
- # @param name [String] rewrtier name.
50
- # @return [Synvert::Rewriter] the matching rewriter.
51
- def fetch(name)
52
- @rewriters[name]
53
- end
54
-
55
- # Get a registered rewriter by name and process that rewriter.
56
- #
57
- # @param name [String] the rewriter name.
58
- # @return [Synvert::Rewriter] the registered rewriter.
59
- # @raise [Synvert::RewriterNotFound] if the registered rewriter is not found.
60
- def call(name)
61
- if (rewriter = @rewriters[name])
62
- rewriter.process
63
- rewriter
64
- else
65
- raise RewriterNotFound.new "Rewriter #{name} not found"
66
- end
67
- end
68
-
69
- # Get all available rewriters
70
- #
71
- # @return [Array<Synvert::Rewriter>]
72
- def availables
73
- @rewriters.values
74
- end
75
-
76
- # Clear all registered rewriters.
77
- def clear
78
- @rewriters.clear
79
- end
80
- end
81
-
82
- # @!attribute [r] name
83
- # @return [String] the unique name of rewriter
84
- # @!attribute [r] sub_snippets
85
- # @return [Array<Synvert::Rewriter>] all rewriters this rewiter calls.
86
- attr_reader :name, :sub_snippets
87
-
88
- # Initialize a rewriter.
89
- # When a rewriter is initialized, it is also registered.
90
- #
91
- # @param name [String] name of the rewriter.
92
- # @param block [Block] a block defines the behaviors of the rewriter, block code won't be called when initialization.
93
- # @return [Synvert::Rewriter]
94
- def initialize(name, &block)
95
- @name = name.to_s
96
- @block = block
97
- @helpers = []
98
- @sub_snippets = []
99
- self.class.register(@name, self)
100
- end
101
-
102
- # Process the rewriter.
103
- # It will call the block.
104
- def process
105
- self.instance_eval &@block
106
- end
107
-
108
- # Process rewriter with sandbox mode.
109
- # It will call the block but doesn't change any file.
110
- def process_with_sandbox
111
- @sandbox = true
112
- self.process
113
- @sandbox = false
114
- end
115
-
116
- #######
117
- # DSL #
118
- #######
119
-
120
- # Parse description dsl, it sets description of the rewrite.
121
- # Or get description.
122
- #
123
- # @param description [String] rewriter description.
124
- # @return rewriter description.
125
- def description(description=nil)
126
- if description
127
- @description = description
128
- else
129
- @description
130
- end
131
- end
132
-
133
- # Parse if_gem dsl, it compares version of the specified gem.
134
- #
135
- # @param name [String] gem name.
136
- # @param comparator [Hash] equal, less than or greater than specified version, e.g. {gte: '2.0.0'},
137
- # key can be eq, lt, gt, lte, gte or ne.
138
- def if_gem(name, comparator)
139
- @gem_spec = Rewriter::GemSpec.new(name, comparator)
140
- end
141
-
142
- # Parse within_files dsl, it finds specified files.
143
- # It creates a [Synvert::Rewriter::Instance] to rewrite code.
144
- #
145
- # @param file_pattern [String] pattern to find files, e.g. spec/**/*_spec.rb
146
- # @param block [Block] the block to rewrite code in the matching files.
147
- def within_files(file_pattern, &block)
148
- return if @sandbox
149
-
150
- if !@gem_spec || @gem_spec.match?
151
- instance = Rewriter::Instance.new(file_pattern, &block)
152
- @helpers.each { |helper| instance.singleton_class.send(:define_method, helper[:name], &helper[:block]) }
153
- instance.process
154
- end
155
- end
156
-
157
- # Parse within_file dsl, it finds a specifiled file.
158
- alias within_file within_files
159
-
160
- # Parses add_file dsl, it adds a new file.
161
- #
162
- # @param filename [String] file name of newly created file.
163
- # @param content [String] file body of newly created file.
164
- def add_file(filename, content)
165
- return if @sandbox
166
-
167
- File.open filename, 'w' do |file|
168
- file.write content
169
- end
170
- end
171
-
172
- # Parse add_snippet dsl, it calls anther rewriter.
173
- #
174
- # @param name [String] name of another rewriter.
175
- def add_snippet(name)
176
- @sub_snippets << self.class.call(name.to_s)
177
- end
178
-
179
- # Parse helper_method dsl, it defines helper method for [Synvert::Rewriter::Instance].
180
- #
181
- # @param name [String] helper method name.
182
- # @param block [Block] helper method block.
183
- def helper_method(name, &block)
184
- @helpers << {name: name, block: block}
185
- end
186
-
187
- # Parse todo dsl, it sets todo of the rewriter.
188
- # Or get todo.
189
- #
190
- # @param todo_list [String] rewriter todo.
191
- # @return [String] rewriter todo.
192
- def todo(todo=nil)
193
- if todo
194
- @todo = todo
195
- else
196
- @todo
197
- end
198
- end
199
- end
200
- end
@@ -1,5 +0,0 @@
1
- Synvert::Rewriter.new :check_syntax do
2
- description "just used to check if there are syntax errors."
3
-
4
- within_files "**/*.rb" do; end
5
- end
@@ -1,98 +0,0 @@
1
- Synvert::Rewriter.new "factory_girl_short_syntax" do
2
- description <<-EOF
3
- Uses FactoryGirl short syntax.
4
-
5
- 1. it adds FactoryGirl::Syntax::methods module to RSpec, Test::Unit, Cucumber, Spainach, MiniTest, MiniTest::Spec, minitest-rails.
6
-
7
- # rspec
8
- RSpec.configure do |config|
9
- config.include FactoryGirl::Syntax::Methods
10
- end
11
-
12
- # Test::Unit
13
- class Test::Unit::TestCase
14
- include FactoryGirl::Syntax::Methods
15
- end
16
-
17
- # Cucumber
18
- World(FactoryGirl::Syntax::Methods)
19
-
20
- # Spinach
21
- class Spinach::FeatureSteps
22
- include FactoryGirl::Syntax::Methods
23
- end
24
-
25
- # MiniTest
26
- class MiniTest::Unit::TestCase
27
- include FactoryGirl::Syntax::Methods
28
- end
29
-
30
- # MiniTest::Spec
31
- class MiniTest::Spec
32
- include FactoryGirl::Syntax::Methods
33
- end
34
-
35
- # minitest-rails
36
- class MiniTest::Rails::ActiveSupport::TestCase
37
- include FactoryGirl::Syntax::Methods
38
- end
39
-
40
- 2. it converts to short syntax.
41
-
42
- FactoryGirl.create(...) => create(...)
43
- FactoryGirl.build(...) => build(...)
44
- FactoryGirl.attributes_for(...) => attributes_for(...)
45
- FactoryGirl.build_stubbed(...) => build_stubbed(...)
46
- FactoryGirl.create_list(...) => create_list(...)
47
- FactoryGirl.build_list(...) => build_list(...)
48
- FactoryGirl.create_pair(...) => create_pair(...)
49
- FactoryGirl.build_pair(...) => build_pair(...)
50
- EOF
51
-
52
- if_gem 'factory_girl', {gte: '2.0.0'}
53
-
54
- # insert include FactoryGirl::Syntax::Methods
55
- within_file 'spec/spec_helper.rb' do
56
- within_node type: 'block', caller: {receiver: 'RSpec', message: 'configure'} do
57
- unless_exist_node type: 'send', message: 'include', arguments: ['FactoryGirl::Syntax::Methods'] do
58
- insert "{{arguments.first}}.include FactoryGirl::Syntax::Methods"
59
- end
60
- end
61
- end
62
-
63
- # insert include FactoryGirl::Syntax::Methods
64
- within_file 'test/test_helper.rb' do
65
- %w(Test::Unit::TestCase ActiveSupport::TestCase MiniTest::Unit::TestCase MiniTest::Spec MiniTest::Rails::ActiveSupport::TestCase).each do |class_name|
66
- within_node type: 'class', name: class_name do
67
- unless_exist_node type: 'send', message: 'include', arguments: ['FactoryGirl::Syntax::Methods'] do
68
- insert "include FactoryGirl::Syntax::Methods"
69
- end
70
- end
71
- end
72
- end
73
-
74
- # insert World(FactoryGirl::Syntax::Methods)
75
- within_file 'features/support/env.rb' do
76
- unless_exist_node type: 'send', message: 'World', arguments: ['FactoryGirl::Syntax::Methods'] do
77
- insert "World(FactoryGirl::Syntax::Methods)"
78
- end
79
- end
80
-
81
- # FactoryGirl.create(...) => create(...)
82
- # FactoryGirl.build(...) => build(...)
83
- # FactoryGirl.attributes_for(...) => attributes_for(...)
84
- # FactoryGirl.build_stubbed(...) => build_stubbed(...)
85
- # FactoryGirl.create_list(...) => create_list(...)
86
- # FactoryGirl.build_list(...) => build_list(...)
87
- # FactoryGirl.create_pair(...) => create_pair(...)
88
- # FactoryGirl.build_pair(...) => build_pair(...)
89
- %w(test/**/*.rb spec/**/*.rb features/**/*.rb).each do |file_pattern|
90
- within_files file_pattern do
91
- %w(create build attributes_for build_stubbed create_list build_list create_pair build_pair).each do |message|
92
- with_node type: 'send', receiver: 'FactoryGirl', message: message do
93
- replace_with "#{message}({{arguments}})"
94
- end
95
- end
96
- end
97
- end
98
- end
@@ -1,93 +0,0 @@
1
- Synvert::Rewriter.new "convert_rails_dynamic_finders" do
2
- description <<-EOF
3
- It converts rails dynamic finders to arel syntax.
4
-
5
- find_all_by_... => where(...)
6
- find_by_... => where(...).first
7
- find_last_by_... => where(...).last
8
- scoped_by_... => where(...)
9
- find_or_initialize_by_... => find_or_initialize_by(...)
10
- find_or_create_by_... => find_or_create_by(...)
11
- EOF
12
-
13
- helper_method 'dynamic_finder_to_hash' do |prefix|
14
- fields = node.message.to_s[prefix.length..-1].split("_and_")
15
- if fields.length == node.arguments.length && :hash != node.arguments.first.type
16
- fields.length.times.map { |i|
17
- fields[i] + ": " + node.arguments[i].source(self)
18
- }.join(", ")
19
- else
20
- "{{arguments}}"
21
- end
22
- end
23
-
24
- within_files '**/*.rb' do
25
- # find_all_by_... => where(...)
26
- with_node type: 'send', message: /^find_all_by_/ do
27
- hash_params = dynamic_finder_to_hash("find_all_by_")
28
- if node.receiver
29
- replace_with "{{receiver}}.where(#{hash_params})"
30
- else
31
- replace_with "where(#{hash_params})"
32
- end
33
- end
34
-
35
- # find_by_... => where(...).first
36
- with_node type: 'send', message: /^find_by_/ do
37
- if :find_by_id == node.message
38
- if node.receiver
39
- replace_with "{{receiver}}.find({{arguments}})"
40
- else
41
- replace_with "find({{arguments}}"
42
- end
43
- elsif :find_by_sql != node.message
44
- hash_params = dynamic_finder_to_hash("find_by_")
45
- if node.receiver
46
- replace_with "{{receiver}}.where(#{hash_params}).first"
47
- else
48
- replace_with "where(#{hash_params}).first"
49
- end
50
- end
51
- end
52
-
53
- # find_last_by_... => where(...).last
54
- with_node type: 'send', message: /^find_last_by_/ do
55
- hash_params = dynamic_finder_to_hash("find_last_by_")
56
- if node.receiver
57
- replace_with "{{receiver}}.where(#{hash_params}).last"
58
- else
59
- replace_with "where(#{hash_params}).last"
60
- end
61
- end
62
-
63
- # scoped_by_... => where(...)
64
- with_node type: 'send', message: /^scoped_by_/ do
65
- hash_params = dynamic_finder_to_hash("scoped_by_")
66
- if node.receiver
67
- replace_with "{{receiver}}.where(#{hash_params})"
68
- else
69
- replace_with "where(#{hash_params})"
70
- end
71
- end
72
-
73
- # find_or_initialize_by_... => find_or_initialize_by(...)
74
- with_node type: 'send', message: /^find_or_initialize_by_/ do
75
- hash_params = dynamic_finder_to_hash("find_or_initialize_by_")
76
- if node.receiver
77
- replace_with "{{receiver}}.find_or_initialize_by(#{hash_params})"
78
- else
79
- replace_with "find_or_initialize_by(#{hash_params})"
80
- end
81
- end
82
-
83
- # find_or_create_by_... => find_or_create_by(...)
84
- with_node type: 'send', message: /^find_or_create_by_/ do
85
- hash_params = dynamic_finder_to_hash("find_or_create_by_")
86
- if node.receiver
87
- replace_with "{{receiver}}.find_or_create_by(#{hash_params})"
88
- else
89
- replace_with "find_or_create_by(#{hash_params})"
90
- end
91
- end
92
- end
93
- end