Class: Railscheck::Test::RailsDeprecations

Inherits:
Railscheck::TestCase show all
Defined in:
lib/test/tc_rails_deprecations.rb

Instance Method Summary collapse

Methods inherited from Railscheck::TestCase

#default_test

Instance Method Details

#test_deprecationsObject

Adapted from code by Mislav Marohnić (pastie.caboo.se/private/krcevozww61drdeza13e3a) merged with code from deprecated plugin by Geoffrey Grosenbach (topfunky.net/svn/plugins/deprecated/) and added my own file deprecation support, simplified reporting, a version-specification and a explicit RAILS-ROOT etc.

TODO: Move yaml specifications into sperate file (regular expressions will have to be updated).



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/test/tc_rails_deprecations.rb', line 13

def test_deprecations      
  specs = YAML::load "  rhtml:\n    pattern: '\\\\.rhtml'\n    where: filename  \n    info: '*.rhtml file extensions are deprecated in favor of *.erb'\n    solution: 'Rename your rhtml files'\n    version: 2.0\n\n  rxml:\n    pattern: '\\\\.rxml'\n    where: filename\n    info: '*.rxml file extensions are deprecated in favor of *.builder'\n    solution: 'Rename your rxml files'\n    version: 2.0\n\n  params instance:\n    pattern: '@params\\\\b'\n    where: controllers\n    info: 'Build-in instance variables has been removed in favor of accessors'\n    solution: 'Use params[] instead'\n    version: 1.1\n\n  session instance:\n    pattern: '@session\\\\b'\n    where: controllers\n    info: 'Build-in instance variables has been removed in favor of accessors'\n    solution: 'Use session[] instead'\n    version: 1.1\n\n  flash instance:\n    pattern: '@flash\\\\b'\n    where: controllers\n    info: 'Build-in instance variables has been removed in favor of accessors'\n    solution: 'Use flash[] instead'\n    version: 1.1\n\n  request instance:\n    pattern: '@request\\\\b'\n    where: controllers\n    info: 'Build-in instance variables has been removed in favor of accessors'\n    solution: 'Use request[] instead'\n    version: 1.1\n\n  env instance:\n    pattern: '@env\\\\b'\n    where: controllers\n    info: 'Build-in instance variables has been removed in favor of accessors'\n    solution: 'Use env[] instead'\n    version: 1.1\n\n  render partial:\n    pattern: '\\\\brender_partial\\\\b'\n    where: controllers\n    info: 'Similar render methods has been combined'\n    solution: 'Use render :partial instead'\n    version: 1.1\n\n  component:\n    pattern: 'components\\\\b'\n    where: filename\n    info: 'Use of components are frowned upon'\n    version: 1.1            \n\n  start_form_tag:\n    pattern: 'start_form_tag\\\\b'\n    where: views\n    info: 'start_form_tag has been removed'\n    solution: 'Use form_for instead'\n    version: 1.1            \n\n  start_form_tag:\n    pattern: 'end_form_tag\\\\b'\n    where: views\n    info: 'end_form_tag has been removed'\n    solution: 'Use form_for instead'\n    version: 1.1\n\n  post option:\n    pattern: ':post\\\\s*=>\\\\s*true\\\\b'\n    info: 'post option has been deprecated'\n    solution: 'Use :method => :post instead'\n    version: 1.1\n\n  breakpoint server:\n    pattern: '\\\\bbreakpoint_server\\\\b'\n    where: config\n    info: 'The configuration option has been removed in favor of the better ruby-debug library.'\n    gem: ruby-debug\n    solution: 'Remove the line(s) from configuration since the setting has no effect anymore.  Instead, start `script/server` with the \"-u\" or \"--debugger\" option (or \"-h\" to see all the options).'\n    changeset: 6627\n    version: 2.0\n\n  with_scope:\n    pattern: '[A-Z]\\\\w+\\\\.with_scope\\\\b'\n    info: 'This class method has been declared private to model classes.'\n    solution: \"Don't use it directly.  You can only use it internally from the model class itself.\"\n    changeset: 6909\n    version: 2.0\n    \n  singular resources:\n    pattern: \"\\\\\\\\.resource\\\\\\\\s+[:\\\\\"'](\\\\w+)\"\n    eval: \"File.exist?('app/controllers/' + $1 + '_controller.rb') and line !~ /:controller\\\\\\\\b/\"\n    where: routes\n    info: \"Singular resources map to pluralized controllers now (ie. map_resource(:post) maps to PostsController).\"\n    solution: \"Rename your singular controller(s) to plural or use the :controller option in `map.resource` to override the controller name it maps to.\"\n    changeset: 6922\n    version: 2.0\n    \n  pagination:\n    pattern: '[^.\\\\w](paginate|(?:find|count)_collection_for_pagination|pagination_links(?:_each)?)\\\\b'\n    where: controllers, views\n    changeset: 6992\n    info: \"Pagination has been extracted from Rails core.\"\n    solution: \"Alternative: you can replace your pagination calls with will_paginate (find it on http://rock.errtheblog.com/).\"\n    plugin: svn://errtheblog.com/svn/plugins/classic_pagination\n    version: 2.0\n    \n  push_with_attributes:\n    pattern: '\\\\.push_with_attributes\\\\b'\n    info: This method on associations has been removed from Rails.\n    solution: \"If you need attributes on associations, use has_many :through.\"\n    changeset: 6997\n    version: 2.0\n    \n  find_first or find_all:\n    pattern: '\\\\b(find_first|[A-Z]\\\\w+\\\\.find_all)\\\\b'\n    where: models, controllers\n    info: \"AR::Base `find_first` and `find_all` class methods have been removed.  (If you're in fact using `find_all` method of Enumerable, ignore this warning.)\"\n    solution: \"Use `find(:first)` or `find(:all)`.\"\n    changeset: 6998\n    version: 2.0\n    \n  Hash.create_from_xml:\n    pattern: '\\\\bHash.create_from_xml\\\\b'\n    info: \"`Hash.create_from_xml` has been renamed to `from_xml`.\"\n    changeset: 7085\n    version: 2.0\n    \n  nested resource named routes:\n    pattern: '\\\\b\\\\w+_(new|edit)_\\\\w+_(url|path)\\\\b'\n    where: controllers, views\n    info: \"Nested resource named routes are now prefixed by their action name.\"\n    solution: \"Rename your calls to such named routes from ie. 'group_new_user_path' to 'new_group_user_path'.  Same applies for 'edit' paths.\"\n    changeset: 7138\n    version: 2.0\n    \n  belongs_to foreign key assumption:\n    pattern: '\\\\bbelongs_to\\\\b.+:class_name\\\\b'\n    eval: 'line !~ /:foreign_key\\\\b/'\n    where: models\n    info: \"The foreign key name is no longer inferred from the explicit class name, but from the association name.\"\n    solution: \"Make sure the foreign key for your association is in the form of '{association_name}_id'.  (See the changeset for an example).\"\n    changeset: 7188\n    version: 2.0\n    \n  old association dependencies:\n    pattern: ':dependent\\\\s*=>\\\\s*true|:exclusively_dependent\\\\b'\n    where: models\n    info: \"Specifying dependencies in associations has a new form and the old API has been removed.\"\n    solution: \"Change ':dependent => true' to ':dependent => :destroy' and ':exclusively_dependent' to ':dependent => :delete_all'.\"\n    changeset: 7402\n    version: 2.0\n    \n  old render methods:\n    pattern: '\\\\brender_(action|with(out)?_layout|file|text|template)\\\\b'\n    where: controllers\n    info: \"The old `render_{something}` API has been removed.\"\n    solution: \"Change `render_action` to `render :action`, `render_text` to `render :text` (and so on) in your controllers.\"\n    changeset: 7403\n    version: 2.0\n    \n  template root:\n    pattern: '\\\\btemplate_root\\\\b'\n    info: \"`template_root` has been dropped in favor of `view_paths` array.\"\n    solution: 'Replace `template_root = \"some/dir\"` with `view_paths = \"some/dir\"`.'\n    changeset: 7426\n    version: 2.0\n    \n  expire matched fragments:\n    pattern: '\\\\bexpire_matched_fragments\\\\b'\n    where: controllers\n    info: \"`expire_matched_fragments` has been superseded by `expire_fragment`.\"\n    solution: \"Simply call `expire_fragment` with a regular expression.\"\n    changeset: 7427\n    version: 2.0\n    \n  expire matched fragments:\n    pattern: '\\\\bkeep_flash\\\\b'\n    where: controllers\n    info: \"`keep flash` has been superseded by `flash.keep`.\"\n    changeset: 7428\n    version: 2.0\n    \n  dynamic scaffold:\n    pattern: '\\\\bscaffold\\\\b'\n    where: controllers\n    plugin: scaffolding\n    info: \"Dynamic scaffolding has gone the way of the dinosaurs.\"\n    solution: \"Don't use it.  Use the 'scaffold' generator to generate scaffolding for RESTful resources.\"\n    changeset: 7429\n    version: 2.0\n    \n  image tag without extension:\n    pattern: \"\\\\\\\\bimage_tag\\\\s*(\\\\(\\\\s*)?('[^'.]+'|\\\\\"[^\\\\\".]+\\\\\")\"\n    where: views\n    info: \".png is no longer the default extension for images.\"\n    solution: \"Explicitly set the image extension when using `image_tag`: instead of just `image_tag 'logo'`, use 'logo.png'.\"\n    changeset: 7432\n    version: 2.0\n    \n  cookie:\n    pattern: ^\\\\s*cookie\\\\b\n    where: controllers\n    info: \"The `cookie` writer method was removed from controllers.\"\n    solution: \"Use `cookies[name] = value` instead.\"\n    changeset: 7434\n    version: 2.0\n    \n  javascript in-place editor:\n    pattern: \\\\b(in_place_editor_field|in_place_edit_for)\\\\b\n    where: views, controllers\n    plugin: in_place_editing\n    info: \"The in-place editor has been extracted from Rails core.\"\n    changeset: 7442\n    version: 2.0\n    \n  javascript autocompleter:\n    pattern: \\\\b(auto_complete_field|auto_complete_for)\\\\b\n    where: views, controllers\n    plugin: auto_complete\n    info: \"The autocompleter has been extracted from Rails core.\"\n    changeset: 7450\n    version: 2.0\n    \n  acts_as_list:\n    pattern: \\\\bacts_as_list\\\\b\n    where: models\n    plugin: acts_as_list\n    info: \"acts_as_list has been extracted from Rails core.\"\n    changeset: 7444\n    version: 2.0\n    \n  acts_as_nested_set:\n    pattern: \\\\bacts_as_nested_set\\\\b\n    where: models\n    plugin: acts_as_nested_set\n    info: \"acts_as_nested_set has been extracted from Rails core.\"\n    changeset: 7453\n    version: 2.0\n    \n  acts_as_tree:\n    pattern: \\\\bacts_as_tree\\\\b\n    where: models\n    plugin: acts_as_tree\n    info: \"acts_as_tree has been extracted from Rails core.\"\n    changeset: 7454\n    version: 2.0\n    \n  reloadable:\n    pattern: \\\\binclude\\\\s+Reloadable\\\\b\n    info: \"Reloadable module is removed from Rails.\"\n    solution: \"Don't include the module anymore. Dependencies code is smart enough to reload classes if they're not in 'load_once' paths.\"\n    changeset: 7473\n    version: 2.0\n"
   
  for props in specs.values
    next unless props['pattern']
    props['pattern'] = Regexp.new props['pattern']
  end
  
  files = (Dir["#{RAILS_ROOT}/{app,config,db/migrate,lib,test}/**/*.rb"] + Dir["#{RAILS_ROOT}/app/views/**/*.{rhtml,rxml,erb,builder,haml}"]).sort
  files -= ["#{RAILS_ROOT}/config/boot.rb"]
  files -= version_control_excludes

  plugins = Dir["#{RAILS_ROOT}/vendor/plugins/*"].map{ |p| File.basename p }.sort

  files.each do |filename|
    #puts "Checking "+filename
    for props in specs.values
      if props['where']=='filename' && filename =~ props['pattern'] and (props['eval'].nil? or eval(props['eval']))
        warn "Rails v#{props['version']} deprecation found at #{filename} #{props['info']}. #{props['solution']}"
      end
    end
 
    File.open(filename).each_with_index do |line, ln|
      next if line =~ /^\s*#/ # skip commented lines
      for props in specs.values
        # puts "Checking "+props['pattern'].to_s
        if props['where']
          where = props['where'].scan /\w+/
          next unless where.any? do |place|
            case place
              when 'filename'
                false
              when 'controllers', 'models'
                filename.index("#{RAILS_ROOT}/app/#{place}/") == 0
              when 'views'
                filename.index("#{RAILS_ROOT}/app/views/") == 0  || filename.index("#{RAILS_ROOT}/app/helpers/") == 0
              when 'routes'
                filename == "#{RAILS_ROOT}/config/routes.rb"
              else
                filename.index("#{RAILS_ROOT}/#{place}/") == 0
              end
            end
        end

        if line =~ props['pattern'] and (props['eval'].nil? or eval(props['eval']))
          warn "Rails v#{props['version']} deprecation found at #{filename}:#{ln + 1}: #{props['info']}. #{props['solution']}"
        end
      end
    end
  end        
end