rails-upgrade 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,6 +6,10 @@ Rakefile
6
6
  bin/rails-upgrade
7
7
  lib/rails-upgrade.rb
8
8
  lib/rails-upgrade/cli.rb
9
+ lib/rails-upgrade/errors.rb
10
+ lib/rails-upgrade/upgraders/check.rb
11
+ lib/rails-upgrade/upgraders/gems.rb
12
+ lib/rails-upgrade/upgraders/routes.rb
9
13
  script/console
10
14
  script/destroy
11
15
  script/generate
@@ -17,5 +17,6 @@ begin
17
17
  rescue StandardError => e
18
18
  puts
19
19
  puts "Error: ".red + e.message.white
20
+ puts e.backtrace.join("\n").yellow
20
21
  puts "".reset
21
22
  end
@@ -1,15 +1,15 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
1
+ $:.unshift(File.dirname(__FILE__))
3
2
 
4
3
  module RailsUpgrade
5
- VERSION = '0.0.1'
4
+ VERSION = '0.0.2'
6
5
  end
7
6
 
8
7
  require 'active_support'
9
8
 
10
- require 'rails-upgrade/errors'
9
+ # This is ridiculous but I don't feel like fighting with require
10
+ require File.dirname(__FILE__) + '/rails-upgrade/errors'
11
11
 
12
- require 'rails-upgrade/upgraders/routes'
13
- require 'rails-upgrade/upgraders/gems'
14
- require 'rails-upgrade/upgraders/check'
12
+ require File.dirname(__FILE__) + '/rails-upgrade/upgraders/routes'
13
+ require File.dirname(__FILE__) + '/rails-upgrade/upgraders/gems'
14
+ require File.dirname(__FILE__) + '/rails-upgrade/upgraders/check'
15
15
 
@@ -2,6 +2,10 @@ module RailsUpgrade
2
2
  class CLI
3
3
  class <<self
4
4
  def execute(stdout, arguments=[])
5
+ if arguments.empty?
6
+ raise "Give me a command!"
7
+ end
8
+
5
9
  command = arguments.pop.capitalize
6
10
 
7
11
  if RailsUpgrade::Upgraders.const_defined?(command)
@@ -0,0 +1,7 @@
1
+ class FileNotFoundError < StandardError; end
2
+
3
+ class NotInRailsAppError < StandardError
4
+ def message
5
+ "I'm not in a Rails application!"
6
+ end
7
+ end
@@ -0,0 +1,201 @@
1
+ # This is badly named/architected. Guess who doesn't care right now...?? :)
2
+ require 'open3'
3
+
4
+ module RailsUpgrade
5
+ module Upgraders
6
+ class Check
7
+ def initialize
8
+ @issues = []
9
+
10
+ raise NotInRailsAppError unless File.exist?("config/environment.rb")
11
+ end
12
+
13
+ def check(args)
14
+ the_methods = (self.public_methods - Object.methods) - ["upgrade!", "check"]
15
+
16
+ the_methods.each {|m| send m }
17
+ end
18
+ alias upgrade! check
19
+
20
+ def check_ar_methods
21
+ files = []
22
+ ["find(:all", "find(:first", ":conditions =>", ":joins =>"].each do |v|
23
+ lines = grep_for(v, "app/models/*")
24
+ files += extract_filenames(lines) || []
25
+ end
26
+
27
+ unless files.empty?
28
+ alert(
29
+ "Soon-to-be-deprecated ActiveRecord calls",
30
+ "Methods such as find(:all), find(:first), finds with conditions, and the :joins option will soon be deprecated.",
31
+ "http://m.onkey.org/2010/1/22/active-record-query-interface",
32
+ files
33
+ )
34
+ end
35
+
36
+ lines = grep_for("named_scope", "app/models/*")
37
+ files = extract_filenames(lines)
38
+
39
+ if files
40
+ alert(
41
+ "named_scope is now just scope",
42
+ "The named_scope method has been renamed to just scope.",
43
+ "http://github.com/rails/rails/commit/d60bb0a9e4be2ac0a9de9a69041a4ddc2e0cc914",
44
+ files
45
+ )
46
+ end
47
+ end
48
+
49
+ def check_routes
50
+ files = []
51
+ ["map.", "ActionController::Routing::Routes", ".resources"].each do |v|
52
+ lines = grep_for(v, "config/routes.rb")
53
+ files += extract_filenames(lines) || []
54
+ end
55
+
56
+ unless files.empty?
57
+ alert(
58
+ "Old router API",
59
+ "The router API has totally changed.",
60
+ "http://yehudakatz.com/2009/12/26/the-rails-3-router-rack-it-up/",
61
+ "config/routes.rb"
62
+ )
63
+ end
64
+ end
65
+
66
+ def check_environment
67
+ unless File.exist?("config/application.rb")
68
+ alert(
69
+ "New file needed: config/application.rb",
70
+ "You need to add a config/application.rb.",
71
+ "http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade",
72
+ "config/application.rb"
73
+ )
74
+ end
75
+
76
+ lines = grep_for("config.", "config/environment.rb")
77
+ files = extract_filenames(lines)
78
+
79
+ if files
80
+ alert(
81
+ "Old environment.rb",
82
+ "environment.rb doesn't do what it used to; you'll need to move some of that into application.rb.",
83
+ "http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade",
84
+ "config/environment.rb"
85
+ )
86
+ end
87
+ end
88
+
89
+ def check_gems
90
+ lines = grep_for("config.gem ", "config/*.rb")
91
+ files = extract_filenames(lines)
92
+
93
+ if files
94
+ alert(
95
+ "Old gem bundling (config.gems)",
96
+ "The old way of bundling is gone now. You need a Gemfile for bundler.",
97
+ "http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade",
98
+ files
99
+ )
100
+ end
101
+ end
102
+
103
+ def check_mailers
104
+ lines = grep_for("deliver_", "app/models/* app/controllers/* app/observers/*")
105
+ files = extract_filenames(lines)
106
+
107
+ if files
108
+ alert(
109
+ "Deprecated ActionMailer API",
110
+ "You're using the old ActionMailer API to send e-mails in a controller, model, or observer.",
111
+ "http://lindsaar.net/2010/1/26/new-actionmailer-api-in-rails-3",
112
+ files
113
+ )
114
+ end
115
+
116
+ files = []
117
+ ["recipients ", "attachment ", "subject ", "from "].each do |v|
118
+ lines = grep_for(v, "app/models/*")
119
+ files += extract_filenames(lines) || []
120
+ end
121
+
122
+ unless files.empty?
123
+ alert(
124
+ "Old ActionMailer class API",
125
+ "You're using the old API in a mailer class.",
126
+ "http://lindsaar.net/2010/1/26/new-actionmailer-api-in-rails-3",
127
+ files
128
+ )
129
+ end
130
+ end
131
+
132
+ def check_generators
133
+ generators = Dir.glob("vendor/plugins/**/generators/**/*.rb")
134
+
135
+ unless generators.empty?
136
+ lines = grep_for("def manifest", generators.join(" "))
137
+ files = extract_filenames(lines)
138
+
139
+ if files
140
+ alert(
141
+ "Old Rails generator API",
142
+ "A plugin in the app is using the old generator API (a new one may be available at http://github.com/trydionel/rails3-generators).",
143
+ "http://blog.plataformatec.com.br/2010/01/discovering-rails-3-generators/",
144
+ files
145
+ )
146
+ end
147
+ end
148
+ end
149
+
150
+ def check_plugins
151
+ # This list is off the wiki; will need to be updated often, esp. since RSpec is working on it
152
+ bad_plugins = ["rspec", "rspec-rails", "hoptoad", "authlogic", "nifty-generators",
153
+ "restful_authentication", "searchlogic", "cucumber", "cucumber-rails"]
154
+
155
+ bad_plugins = bad_plugins.map {|p| p if File.exist?("vendor/plugins/#{p}") || !Dir.glob("vendor/gems/#{p}-*").empty?}.compact
156
+
157
+ unless bad_plugins.empty?
158
+ alert(
159
+ "Known broken plugins",
160
+ "At least one plugin in your app is broken (according to the wiki). Most of project maintainers are rapidly working towards compatability, but do be aware you may encounter issues.",
161
+ "http://wiki.rubyonrails.org/rails/version3/plugins_and_gems",
162
+ bad_plugins
163
+ )
164
+ end
165
+ end
166
+
167
+ private
168
+ def grep_for(text, where = "*")
169
+ value = ""
170
+
171
+ # TODO: Figure out a pure Ruby way to do this that doesn't suck
172
+ Open3.popen3("grep -r '#{text}' #{where}") do |stdin, stdout, stderr|
173
+ value = stdout.read
174
+ end
175
+
176
+ value
177
+ end
178
+
179
+ def extract_filenames(output)
180
+ return nil if output.empty?
181
+
182
+ # I hate rescue nil as much as the next guy but I have a reason here at least...
183
+ fnames = output.split("\n").map {|fn| fn.match(/^(.+?):/)[1] rescue nil}.compact
184
+ fnames.uniq
185
+ end
186
+
187
+ def alert(title, text, more_info_url, culprits)
188
+ puts title.red.bold
189
+ puts text.white
190
+ puts "More information: ".white.bold + more_info_url.blue
191
+ puts
192
+ puts "The culprits: ".white
193
+ culprits.each do |c|
194
+ puts "\t- #{c}".yellow
195
+ end
196
+ ensure
197
+ puts "".reset
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,73 @@
1
+ module RailsUpgrade
2
+ module Upgraders
3
+ class Gems
4
+ def upgrade!(args)
5
+ if File.exists?("config/environment.rb")
6
+ generate_gemfile
7
+ else
8
+ raise FileNotFoundError, "Can't find environment.rb [config/environment.rb]!"
9
+ end
10
+ end
11
+
12
+ def generate_gemfile
13
+ environment_file = File.open("config/environment.rb").read
14
+
15
+ # Get each line that starts with config.gem
16
+ gem_lines = environment_file.split("\n").select {|l| l =~ /^\s*config\.gem/}
17
+
18
+ # yay hax
19
+ config = GemfileGenerator.new
20
+ eval(gem_lines.join("\n"))
21
+ puts config.output
22
+ end
23
+ end
24
+
25
+ class GemfileGenerator
26
+ def initialize
27
+ @gems = []
28
+ end
29
+
30
+ def gem(name, options={})
31
+ data = {}
32
+
33
+ # Add new keys from old keys
34
+ data[:require_as] = options[:lib] if options[:lib]
35
+ data[:source] = options[:source] if options[:source]
36
+
37
+ version = options[:version]
38
+ @gems << [name, version, data]
39
+ end
40
+
41
+ def output
42
+ preamble = <<STR
43
+ # Edit this Gemfile to bundle your application's dependencies.
44
+ # This preamble is the current preamble for Rails 3 apps; edit as needed.
45
+ directory "/path/to/rails", :glob => "{*/,}*.gemspec"
46
+ git "git://github.com/rails/arel.git"
47
+ git "git://github.com/rails/rack.git"
48
+ gem "rails", "3.0.pre"
49
+ STR
50
+ preamble + "\n" + generate_upgraded_code
51
+ end
52
+
53
+ def generate_upgraded_code
54
+ code = @gems.map do |name, version, data|
55
+ version_string = (version ? ", '#{version}'" : "")
56
+ source = data.delete(:source)
57
+ # omg hax. again.
58
+ data_string = ""
59
+
60
+ unless data.empty?
61
+ data_string = data.inspect.match(/^\{(.*)\}$/)[1]
62
+ end
63
+
64
+ if source
65
+ "source '#{source}'\ngem '#{name}'#{version_string}#{data_string}"
66
+ else
67
+ "gem '#{name}'#{version_string}, #{data_string}"
68
+ end
69
+ end.join("\n")
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,318 @@
1
+ DEBUG = false
2
+
3
+ # TODO: Formatting on member/collection methods
4
+
5
+ module RailsUpgrade
6
+ module Upgraders
7
+ class Routes
8
+ def upgrade!(args)
9
+ if File.exists?("config/routes.rb")
10
+ upgrade_routes
11
+ else
12
+ raise FileNotFoundError, "Can't find your routes file [config/routes.rb]!"
13
+ end
14
+ end
15
+
16
+ def upgrade_routes
17
+ ActionController::Routing::Routes.setup
18
+
19
+ eval(File.read("config/routes.rb"))
20
+
21
+ generator = RouteGenerator.new(ActionController::Routing::Routes.redrawer.routes)
22
+ puts generator.generate
23
+ end
24
+ end
25
+
26
+ class RouteRedrawer
27
+ attr_accessor :routes
28
+ cattr_accessor :stack
29
+
30
+ def initialize
31
+ @routes = []
32
+ @default_route_generated = false
33
+
34
+ # Setup the stack for parents
35
+ self.class.stack = [@routes]
36
+ end
37
+
38
+ def root(options)
39
+ debug "mapping root"
40
+ @routes << FakeRoute.new("/", options)
41
+ end
42
+
43
+ def connect(path, options={})
44
+ debug "connecting #{path}"
45
+
46
+ if (path == ":controller/:action/:id.:format" || path == ":controller/:action/:id")
47
+ if !@default_route_generated
48
+ current_parent << FakeRoute.new("/:controller(/:action(/:id))", {:default_route => true})
49
+
50
+ @default_route_generated = true
51
+ end
52
+ else
53
+ current_parent << FakeRoute.new(path, options)
54
+ end
55
+ end
56
+
57
+ def resources(*args)
58
+ if block_given?
59
+ parent = FakeResourceRoute.new(args.shift)
60
+ debug "mapping resources #{parent.name} with block"
61
+
62
+ parent = stack(parent) do
63
+ yield(self)
64
+ end
65
+
66
+ current_parent << parent
67
+ else
68
+ if args.last.is_a?(Hash)
69
+ current_parent << FakeResourceRoute.new(args.shift, args.pop)
70
+ debug "mapping resources #{current_parent.last.name} w/o block with args"
71
+ else
72
+ args.each do |a|
73
+ current_parent << FakeResourceRoute.new(a)
74
+ debug "mapping resources #{current_parent.last.name}"
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ def resource(*args)
81
+ if block_given?
82
+ parent = FakeSingletonResourceRoute.new(args.shift)
83
+ debug "mapping resource #{parent.name} with block"
84
+
85
+ parent = stack(parent) do
86
+ yield(self)
87
+ end
88
+
89
+ current_parent << parent
90
+ else
91
+ if args.last.is_a?(Hash)
92
+ current_parent << FakeSingletonResourceRoute.new(args.shift, args.pop)
93
+ debug "mapping resources #{current_parent.last.name} w/o block with args"
94
+ else
95
+ args.each do |a|
96
+ current_parent << FakeSingletonResourceRoute.new(a)
97
+ debug "mapping resources #{current_parent.last.name}"
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ def namespace(name)
104
+ debug "mapping namespace #{name}"
105
+ namespace = FakeNamespace.new(name)
106
+
107
+ namespace = stack(namespace) do
108
+ yield(self)
109
+ end
110
+
111
+ current_parent << namespace
112
+ end
113
+
114
+ def method_missing(m, *args)
115
+ debug "named route: #{m}"
116
+ current_parent << FakeRoute.new(args.shift, args.pop, m.to_s)
117
+ end
118
+
119
+ def self.indent
120
+ ' ' * ((stack.length) * 2)
121
+ end
122
+
123
+ private
124
+ def debug(txt)
125
+ puts txt if DEBUG
126
+ end
127
+
128
+ def stack(obj)
129
+ self.class.stack << obj
130
+ yield
131
+ self.class.stack.pop
132
+ end
133
+
134
+ def current_parent
135
+ self.class.stack.last
136
+ end
137
+ end
138
+
139
+ class RouteObject
140
+ def indent_lines(code_lines)
141
+ if code_lines.length > 1
142
+ code_lines.flatten.map {|l| "#{@indent}#{l.chomp}"}.join("\n") + "\n"
143
+ else
144
+ "#{@indent}#{code_lines.shift}"
145
+ end
146
+ end
147
+
148
+ def opts_to_string(opts)
149
+ # omg hax. again.
150
+ opts.is_a?(Hash) ? opts.inspect.match(/^\{(.*)\}$/)[1] : nil
151
+ end
152
+ end
153
+
154
+ class FakeNamespace < RouteObject
155
+ attr_accessor :routes, :name
156
+
157
+ def initialize(name)
158
+ @routes = []
159
+ @name = name
160
+ @indent = RouteRedrawer.indent
161
+ end
162
+
163
+ def to_route_code
164
+ lines = ["namespace :#{@name} do", @routes.map {|r| r.to_route_code}, "end"]
165
+
166
+ indent_lines(lines)
167
+ end
168
+
169
+ def <<(val)
170
+ @routes << val
171
+ end
172
+
173
+ def last
174
+ @routes.last
175
+ end
176
+ end
177
+
178
+ class FakeRoute < RouteObject
179
+ attr_accessor :name, :path, :options
180
+
181
+ def initialize(path, options, name = "")
182
+ @path = path
183
+ @options = options || {}
184
+ @name = name
185
+ @indent = RouteRedrawer.indent
186
+ end
187
+
188
+ def to_route_code
189
+ if @options[:default_route]
190
+ indent_lines ["match '#{@path}'"]
191
+ else
192
+ base = "match '%s' => '%s#%s'"
193
+ extra_options = []
194
+
195
+ if not name.empty?
196
+ extra_options << ":as => :#{name}"
197
+ end
198
+
199
+ if @options[:requirements]
200
+ @options[:constraints] = @options.delete(:requirements)
201
+ end
202
+
203
+ if @options[:conditions]
204
+ @options[:via] = @options.delete(:conditions).delete(:method)
205
+ end
206
+
207
+ @options ||= {}
208
+ base = (base % [@path, @options.delete(:controller), (@options.delete(:action) || "index")])
209
+ opts = opts_to_string(@options)
210
+
211
+ route_pieces = ([base] + extra_options + [opts])
212
+ route_pieces.delete("")
213
+
214
+ indent_lines [route_pieces.join(", ")]
215
+ end
216
+ end
217
+ end
218
+
219
+ class FakeResourceRoute < RouteObject
220
+ attr_accessor :name, :children
221
+
222
+ def initialize(name, options = {})
223
+ @name = name
224
+ @children = []
225
+ @options = options
226
+ @indent = RouteRedrawer.indent
227
+ end
228
+
229
+ def to_route_code
230
+
231
+ if !@children.empty? || @options.has_key?(:collection) || @options.has_key?(:member)
232
+ prefix = ["#{route_method} :#{@name} do"]
233
+ lines = prefix + custom_methods + [@children.map {|r| r.to_route_code}.join("\n"), "end"]
234
+
235
+ indent_lines(lines)
236
+ else
237
+ base = "#{route_method} :%s"
238
+ indent_lines [base % [@name]]
239
+ end
240
+ end
241
+
242
+ def custom_methods
243
+ collection_code = generate_custom_methods_for(:collection)
244
+ member_code = generate_custom_methods_for(:member)
245
+ [collection_code, member_code]
246
+ end
247
+
248
+ def generate_custom_methods_for(group)
249
+ return "" unless @options[group]
250
+
251
+ method_code = []
252
+
253
+ RouteRedrawer.stack << self
254
+ @options[group].each do |k, v|
255
+ method_code << "#{v} :#{k}"
256
+ end
257
+ RouteRedrawer.stack.pop
258
+
259
+ indent_lines ["#{group} do", method_code, "end"].flatten
260
+ end
261
+
262
+ def route_method
263
+ "resources"
264
+ end
265
+
266
+ def <<(val)
267
+ @children << val
268
+ end
269
+
270
+ def last
271
+ @children.last
272
+ end
273
+ end
274
+
275
+ class FakeSingletonResourceRoute < FakeResourceRoute
276
+ def route_method
277
+ "resource"
278
+ end
279
+ end
280
+
281
+ class RouteGenerator
282
+ def initialize(routes)
283
+ @routes = routes
284
+ @new_code = ""
285
+ end
286
+
287
+ def generate
288
+ @new_code = @routes.map do |r|
289
+ r.to_route_code
290
+ end.join("\n")
291
+
292
+ "#{app_name.classify}::Application.routes do\n#{@new_code}\nend\n"
293
+ end
294
+ private
295
+ def app_name
296
+ File.basename(Dir.pwd)
297
+ end
298
+ end
299
+ end
300
+ end
301
+
302
+ module ActionController
303
+ module Routing
304
+ class Routes
305
+ def self.setup
306
+ @redrawer = RailsUpgrade::Upgraders::RouteRedrawer.new
307
+ end
308
+
309
+ def self.redrawer
310
+ @redrawer
311
+ end
312
+
313
+ def self.draw
314
+ yield @redrawer
315
+ end
316
+ end
317
+ end
318
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-upgrade
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy McAnally
@@ -82,6 +82,10 @@ files:
82
82
  - bin/rails-upgrade
83
83
  - lib/rails-upgrade.rb
84
84
  - lib/rails-upgrade/cli.rb
85
+ - lib/rails-upgrade/errors.rb
86
+ - lib/rails-upgrade/upgraders/check.rb
87
+ - lib/rails-upgrade/upgraders/gems.rb
88
+ - lib/rails-upgrade/upgraders/routes.rb
85
89
  - script/console
86
90
  - script/destroy
87
91
  - script/generate