refactoring 0.0.1

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.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in refactoring.gemspec
4
+ gemspec
data/README ADDED
File without changes
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate refactoring Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,22 @@
1
+ module Refactoring
2
+ module Generators
3
+ class RefactorizationGenerator < Rails::Generators::NamedBase
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ def initialize_names
7
+ @version = Time.now.utc.strftime("%Y%m%d%H%M%S")
8
+ @versions_file_name = "#{Refactoring::REFACTORIZATIONS_ROOT}/versions"
9
+ @file_name = "#{@version}_#{name}.rb"
10
+ @class_name = name.classify
11
+ end
12
+
13
+ def generate_versions_file
14
+ create_file @versions_file_name unless File.exists?(@versions_file_name)
15
+ end
16
+
17
+ def generate_refactoring
18
+ template "refactoring.rb", "#{Refactoring::REFACTORIZATIONS_ROOT}/#{@file_name}"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,7 @@
1
+ class <%= @class_name %> < Refactoring::Base
2
+ def up
3
+ end
4
+
5
+ def down
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate refactoring Thing
6
+
7
+ This will create:
8
+ what/will/it/create
9
+
@@ -0,0 +1,36 @@
1
+ module Refactoring
2
+ module Generators
3
+ class RunGenerator < Rails::Generators::Base
4
+ def run_refactorizations
5
+ Dir.glob(Rails.root.to_s + "/#{Refactoring::REFACTORIZATIONS_ROOT}/2*.rb") do |f|
6
+ if !refactorization_ran?(File.basename(f).split("_")[0])
7
+ run_refactorization(f)
8
+ end
9
+ end
10
+ end
11
+
12
+ private
13
+ def refactorization_ran?(version)
14
+ @versions_file_name ||= Rails.root.to_s + "/#{Refactoring::REFACTORIZATIONS_ROOT}/versions"
15
+ f = File.open(@versions_file_name, "r")
16
+ f.each_line do |line|
17
+ if line.strip == version
18
+ f.close
19
+ return true
20
+ end
21
+ end
22
+ false
23
+ end
24
+
25
+ def run_refactorization(file_name)
26
+ basename = File.basename(file_name, ".rb")
27
+ puts "Running refactorization #{basename}..."
28
+
29
+ require file_name
30
+ class_name = basename.sub(/^.+?_/, "").classify
31
+ instance = eval "#{class_name}.new"
32
+ instance.refactor(:up)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,337 @@
1
+ require 'irb/ruby-lex'
2
+ require 'stringio'
3
+
4
+ module Refactoring
5
+ REFACTORIZATIONS_ROOT = "refactorizations"
6
+
7
+ class Base
8
+ def rename(old, new)
9
+ @names = {
10
+ :old => name_variants(old),
11
+ :new => name_variants(new)
12
+ }
13
+
14
+ puts " - renaming #{@names[:old][:model][:class]} to #{@names[:new][:model][:class]}..."
15
+
16
+ rename_model_file
17
+ rename_model_class
18
+ rename_model_associations
19
+ rename_controller_file
20
+ rename_controller_class
21
+ rename_params
22
+ rename_views_directory
23
+ rename_helper_file
24
+ rename_helper_module
25
+ rename_test_files
26
+ rename_test_classes
27
+ rename_fixture_files
28
+ rename_instance_variables
29
+ rename_routes
30
+ rename_foreign_keys
31
+ generate_table_rename_migration
32
+ rename_scaffold_comments
33
+ end
34
+
35
+ def refactor(direction)
36
+ return unless respond_to?(direction.to_s)
37
+ send(direction)
38
+ end
39
+
40
+ private
41
+ def rename_model_file
42
+ puts " - renaming model file..."
43
+ File.rename(@names[:old][:model][:path], @names[:new][:model][:path])
44
+ end
45
+
46
+ def rename_model_class
47
+ puts " - renaming model class..."
48
+ rename_constant(@names[:old][:model][:class], @names[:new][:model][:class])
49
+ end
50
+
51
+ def rename_model_associations
52
+ puts " - renaming model associations..."
53
+ Dir.glob("#{models_path}/*.rb") do |model_file_name|
54
+ replace_in_file(model_file_name, /((?:^|\n)\s*(?:has_one|belongs_to)\s*:)#{@names[:old][:model][:name][:singular]}/, "\\1#{@names[:new][:model][:name][:singular]}")
55
+ replace_in_file(model_file_name, /((?:^|\n)\s*(?:has_(?:and_belongs_to)?many)\s*:)#{@names[:old][:model][:name][:plural]}/, "\\1#{@names[:new][:model][:name][:plural]}")
56
+ replace_in_file(model_file_name, /(:class_name\s*=>\s*['"])#{@names[:old][:model][:class]}/, "\\1#{@names[:new][:model][:class]}")
57
+ end
58
+ end
59
+
60
+ def rename_controller_file
61
+ puts " - renaming controller file..."
62
+ File.rename(@names[:old][:controller][:path], @names[:new][:controller][:path])
63
+ end
64
+
65
+ def rename_controller_class
66
+ puts " - renaming controller class..."
67
+ rename_constant(@names[:old][:controller][:class], @names[:new][:controller][:class])
68
+ end
69
+
70
+ def rename_views_directory
71
+ puts " - renaming views directory..."
72
+ File.rename(@names[:old][:views][:path], @names[:new][:views][:path])
73
+ end
74
+
75
+ def rename_helper_file
76
+ puts " - renaming helper file..."
77
+ File.rename(@names[:old][:helper][:path], @names[:new][:helper][:path])
78
+ end
79
+
80
+ def rename_helper_module
81
+ puts " - renaming helper module..."
82
+ rename_constant(@names[:old][:helper][:module], @names[:new][:helper][:module])
83
+ end
84
+
85
+ def rename_test_files
86
+ puts " - renaming test files..."
87
+ File.rename(@names[:old][:test][:unit][:path], @names[:new][:test][:unit][:path])
88
+ File.rename(@names[:old][:test][:helper][:path], @names[:new][:test][:helper][:path])
89
+ File.rename(@names[:old][:test][:functional][:path], @names[:new][:test][:functional][:path])
90
+ end
91
+
92
+ def rename_test_classes
93
+ puts " - renaming test classes..."
94
+ rename_constant(@names[:old][:test][:unit][:class], @names[:new][:test][:unit][:class])
95
+ rename_constant(@names[:old][:test][:helper][:class], @names[:new][:test][:helper][:class])
96
+ rename_constant(@names[:old][:test][:functional][:class], @names[:new][:test][:functional][:class])
97
+ end
98
+
99
+ def rename_instance_variables
100
+ puts " - renaming instance variables..."
101
+
102
+ variants = []
103
+ variants << [@names[:old][:model][:name][:singular], @names[:new][:model][:name][:singular]]
104
+ variants << [@names[:old][:model][:name][:plural], @names[:new][:model][:name][:plural]]
105
+
106
+ code_files.each do |file_name|
107
+ variants.each do |variant|
108
+ text_original = File.read(file_name)
109
+ text_changed = rename_instance_variables_in_text(text_original, variant[0], variant[1])
110
+
111
+ if text_changed != text_original
112
+ open(file_name, "w") { |f| f.puts(text_changed) }
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ def rename_scaffold_comments
119
+ puts " - renaming scaffold comments..."
120
+ replace_in_file(@names[:new][:controller][:path], /((?:^|\n)\s*#\s+(?:GET|POST|PUT|DELETE)\s+\/)#{@names[:old][:model][:name][:plural]}/, "\\1#{@names[:new][:model][:name][:plural]}")
121
+ end
122
+
123
+ def rename_fixture_files
124
+ puts " - renaming fixture files..."
125
+ File.rename(@names[:old][:test][:fixtures][:path], @names[:new][:test][:fixtures][:path])
126
+ end
127
+
128
+ def generate_table_rename_migration
129
+ puts " - generating table rename migration..."
130
+ time = Time.now.utc.strftime("%Y%m%d%H%M%S")
131
+ open("#{db_path}/migrate/#{time}_rename_#{@names[:old][:table]}_to_#{@names[:new][:table]}.rb", "w") do |f|
132
+ f.puts "class Rename#{@names[:old][:table].titleize}To#{@names[:new][:table].titleize} < ActiveRecord::Migration\n"
133
+ f.puts " def self.up\n"
134
+ f.puts " rename_table :#{@names[:old][:table]}, :#{@names[:new][:table]}\n"
135
+ f.puts " end\n"
136
+ f.puts "\n"
137
+ f.puts " def self.down\n"
138
+ f.puts " rename_table :#{@names[:new][:table]}, :#{@names[:old][:table]}\n"
139
+ f.puts " end\n"
140
+ f.puts "end\n"
141
+ end
142
+ end
143
+
144
+ def rename_params
145
+ puts " - renaming params..."
146
+ replace_in_file(@names[:new][:controller][:path], /(\bparams\[:)#{@names[:old][:model][:name][:singular]}/, "\\1#{@names[:new][:model][:name][:singular]}")
147
+ end
148
+
149
+ def rename_foreign_keys
150
+ puts " - renaming foreign keys TODO..."
151
+ end
152
+
153
+ def rename_routes
154
+ puts " - renaming routes..."
155
+
156
+ sgo = @names[:old][:model][:name][:singular]
157
+ sgn = @names[:new][:model][:name][:singular]
158
+ plo = @names[:old][:model][:name][:plural]
159
+ pln = @names[:new][:model][:name][:plural]
160
+
161
+ replace_in_file(routes_path, /(\bresources\s+:)#{plo}/, "\\1#{pln}")
162
+ replace_in_file(routes_path, /(\bresource\s+:)#{sgo}/, "\\1#{sgn}")
163
+ replace_in_file(routes_path, /(\b:controller\s*=>\s*['"])#{plo}/, "\\1#{pln}")
164
+
165
+ route_identifiers = {
166
+ plo => pln,
167
+ "new_#{sgo}" => "new_#{sgn}",
168
+ "edit_#{sgo}" => "edit_#{sgn}",
169
+ sgo => sgn
170
+ }
171
+
172
+ code_files.each do |file_name|
173
+ text_original = File.read(file_name)
174
+ text_changed = text_original
175
+
176
+ route_identifiers.each do |from, to|
177
+ {"#{from}_path" => "#{to}_path", "#{from}_url" => "#{to}_url"}.each do |old, new|
178
+ text_changed = rename_identifier_in_text(text_changed, old, new)
179
+ end
180
+ end
181
+
182
+ if text_changed != text_original
183
+ open(file_name, "w") { |f| f.puts(text_changed) }
184
+ end
185
+ end
186
+ end
187
+
188
+ def name_variants(name)
189
+ variants = {
190
+ :model => {:name => {}},
191
+ :controller => {},
192
+ :views => {},
193
+ :helper => {},
194
+ :test => {:unit => {}, :helper => {}, :functional => {}, :fixtures => {}},
195
+ :table => {}
196
+ }
197
+
198
+ variants[:model][:name][:singular] = name.to_s
199
+ variants[:model][:name][:plural] = variants[:model][:name][:singular].pluralize
200
+ variants[:model][:class] = variants[:model][:name][:singular].classify
201
+ variants[:model][:path] = "#{models_path}/#{name.to_s}.rb"
202
+
203
+ variants[:controller][:name] = "#{variants[:model][:name][:plural]}_controller"
204
+ variants[:controller][:class] = variants[:controller][:name].classify
205
+ variants[:controller][:path] = "#{controllers_path}/#{variants[:controller][:name]}.rb"
206
+
207
+ variants[:views][:path] = "#{views_path}/#{variants[:model][:name][:plural]}"
208
+
209
+ variants[:helper][:path] = "#{helpers_path}/#{variants[:model][:name][:plural]}_helper.rb"
210
+ variants[:helper][:module] = "#{variants[:model][:class].pluralize}Helper"
211
+
212
+ variants[:test][:unit][:path] = "#{test_path}/unit/#{variants[:model][:name][:singular]}_test.rb"
213
+ variants[:test][:unit][:class] = "#{variants[:model][:class]}Test"
214
+ variants[:test][:helper][:path] = "#{test_path}/unit/helpers/#{variants[:model][:name][:plural]}_helper_test.rb"
215
+ variants[:test][:helper][:class] = "#{variants[:model][:class].pluralize}HelperTest"
216
+ variants[:test][:functional][:path] = "#{test_path}/functional/#{variants[:controller][:name]}_test.rb"
217
+ variants[:test][:functional][:class] = "#{variants[:controller][:class]}Test"
218
+ variants[:test][:fixtures][:path] = "#{test_path}/fixtures/#{variants[:model][:name][:plural]}.yml"
219
+
220
+ variants[:table] = variants[:model][:name][:plural]
221
+
222
+ variants
223
+ end
224
+
225
+ def rename_token_in_text(token_to_find, text, old, new)
226
+ changes = []
227
+
228
+ parser = RubyLex.new
229
+ parser.set_input(StringIO.new(text))
230
+
231
+ loop do
232
+ token = parser.token
233
+ break if token.nil?
234
+
235
+ if token.class == token_to_find && token.name == old
236
+ if changes.length == 0
237
+ changes << token.seek
238
+ else
239
+ changes << token.seek + ((new.length - old.length) * changes.length)
240
+ end
241
+ end
242
+ end
243
+
244
+ changes.each do |offset|
245
+ first_part = text.slice(0, offset)
246
+ last_part = text.slice(offset + old.length, text.length)
247
+ text = first_part + new + last_part
248
+ end
249
+
250
+ text.scan /".+?(?<!\\)"/ms do |quote|
251
+ quote_original = quote
252
+ quote.scan /\#{(.+?(?<!\\))}/ do |code|
253
+ text_original = code[0]
254
+ text_changed = rename_token_in_text(token_to_find, text_original, old, new)
255
+ quote = quote.gsub("\#{#{text_original}}", "\#{#{text_changed}}")
256
+ end
257
+ if quote_original != quote
258
+ text = text.gsub(quote_original, quote)
259
+ end
260
+ end
261
+
262
+ text.scan /((?:assert_.+?|eval)\s*\(?)(["'])(.+?)(?<!\\)\2/ do |method, quote, code|
263
+ text_original = code
264
+ text_changed = rename_token_in_text(token_to_find, text_original, old, new)
265
+ if text_changed != text_original
266
+ text = text.gsub("#{method}#{quote}#{code}", "#{method}#{quote}#{text_changed}")
267
+ end
268
+ end
269
+
270
+ text
271
+ end
272
+
273
+ def rename_constant_in_text(text, old, new)
274
+ rename_token_in_text(RubyToken::TkCONSTANT, text, old, new)
275
+ end
276
+
277
+ def rename_instance_variables_in_text(text, old, new)
278
+ rename_token_in_text(RubyToken::TkIVAR, text, "@#{old}", "@#{new}")
279
+ end
280
+
281
+ def rename_identifier_in_text(text, old, new)
282
+ rename_token_in_text(RubyToken::TkIDENTIFIER, text, old, new)
283
+ end
284
+
285
+ def rename_constant(old, new)
286
+ code_files.each do |file_name|
287
+ text_original = File.read(file_name)
288
+ text_changed = rename_constant_in_text(text_original, old, new)
289
+
290
+ if text_changed != text_original
291
+ open(file_name, "w") { |f| f.puts(text_changed) }
292
+ end
293
+ end
294
+ end
295
+
296
+ def models_path
297
+ @models_path ||= Rails.application.config.paths.app.models.to_a[0]
298
+ end
299
+
300
+ def controllers_path
301
+ @controllers_path ||= Rails.application.config.paths.app.controllers.to_a[0]
302
+ end
303
+
304
+ def views_path
305
+ @views_path ||= Rails.application.config.paths.app.views.to_a[0]
306
+ end
307
+
308
+ def helpers_path
309
+ @helpers_path ||= Rails.application.config.paths.app.helpers.to_a[0]
310
+ end
311
+
312
+ def root_path
313
+ @root_path ||= Rails.root.to_s
314
+ end
315
+
316
+ def test_path
317
+ @test_path ||= "#{root_path}/test"
318
+ end
319
+
320
+ def db_path
321
+ @db_path ||= "#{root_path}/db"
322
+ end
323
+
324
+ def routes_path
325
+ @routes_path ||= "#{root_path}/config/routes.rb"
326
+ end
327
+
328
+ def code_files
329
+ Dir.glob("#{Rails.root}/app/**/*.rb") + Dir.glob("#{Rails.root}/test/**/*.rb")
330
+ end
331
+
332
+ def replace_in_file(file_name, regexp, replacement)
333
+ text = File.read(file_name)
334
+ open(file_name, "w") { |f| f.puts(text.gsub(regexp, replacement)) }
335
+ end
336
+ end
337
+ end
@@ -0,0 +1,3 @@
1
+ module Refactoring
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "refactoring/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "refactoring"
7
+ s.version = Refactoring::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Radu Dineiu"]
10
+ s.email = ["radu.dineiu@gmail.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{Refactoring for Ruby on Rails}
13
+ s.description = %q{Refactoring for Ruby on Rails}
14
+
15
+ s.rubyforge_project = "refactoring"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: refactoring
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Radu Dineiu
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-02-10 00:00:00 +02:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Refactoring for Ruby on Rails
18
+ email:
19
+ - radu.dineiu@gmail.com
20
+ executables: []
21
+
22
+ extensions: []
23
+
24
+ extra_rdoc_files: []
25
+
26
+ files:
27
+ - .gitignore
28
+ - Gemfile
29
+ - README
30
+ - Rakefile
31
+ - lib/generators/refactoring/refactorization/USAGE
32
+ - lib/generators/refactoring/refactorization/refactorization_generator.rb
33
+ - lib/generators/refactoring/refactorization/templates/refactoring.rb
34
+ - lib/generators/refactoring/run/USAGE
35
+ - lib/generators/refactoring/run/run_generator.rb
36
+ - lib/refactoring.rb
37
+ - lib/refactoring/version.rb
38
+ - refactoring.gemspec
39
+ has_rdoc: true
40
+ homepage: ""
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ requirements: []
61
+
62
+ rubyforge_project: refactoring
63
+ rubygems_version: 1.5.0
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: Refactoring for Ruby on Rails
67
+ test_files: []
68
+