rails-upgrade 0.0.1 → 0.0.2

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.
@@ -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