rails_best_practices 0.6.6 → 0.6.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/Gemfile +0 -1
  2. data/README.md +28 -24
  3. data/Rakefile +0 -8
  4. data/install_supported_rubies.sh +2 -3
  5. data/lib/rails_best_practices.rb +8 -7
  6. data/lib/rails_best_practices/core.rb +1 -0
  7. data/lib/rails_best_practices/core/check.rb +68 -0
  8. data/lib/rails_best_practices/core/checking_visitor.rb +18 -15
  9. data/lib/rails_best_practices/core/runner.rb +22 -12
  10. data/lib/rails_best_practices/core/visitable_sexp.rb +6 -2
  11. data/lib/rails_best_practices/prepares.rb +11 -0
  12. data/lib/rails_best_practices/prepares/mailer_prepare.rb +33 -0
  13. data/lib/rails_best_practices/prepares/model_prepare.rb +60 -0
  14. data/lib/rails_best_practices/reviews.rb +23 -0
  15. data/lib/rails_best_practices/{checks/add_model_virtual_attribute_check.rb → reviews/add_model_virtual_attribute_review.rb} +6 -9
  16. data/lib/rails_best_practices/{checks/always_add_db_index_check.rb → reviews/always_add_db_index_review.rb} +9 -12
  17. data/lib/rails_best_practices/{checks/dry_bundler_in_capistrano_check.rb → reviews/dry_bundler_in_capistrano_review.rb} +8 -11
  18. data/lib/rails_best_practices/{checks/isolate_seed_data_check.rb → reviews/isolate_seed_data_review.rb} +11 -14
  19. data/lib/rails_best_practices/{checks/keep_finders_on_their_own_model_check.rb → reviews/keep_finders_on_their_own_model_review.rb} +7 -10
  20. data/lib/rails_best_practices/{checks/law_of_demeter_check.rb → reviews/law_of_demeter_review.rb} +10 -14
  21. data/lib/rails_best_practices/{checks/move_code_into_controller_check.rb → reviews/move_code_into_controller_review.rb} +8 -11
  22. data/lib/rails_best_practices/{checks/move_code_into_helper_check.rb → reviews/move_code_into_helper_review.rb} +7 -10
  23. data/lib/rails_best_practices/{checks/move_code_into_model_check.rb → reviews/move_code_into_model_review.rb} +7 -10
  24. data/lib/rails_best_practices/{checks/move_finder_to_named_scope_check.rb → reviews/move_finder_to_named_scope_review.rb} +7 -10
  25. data/lib/rails_best_practices/{checks/move_model_logic_into_model_check.rb → reviews/move_model_logic_into_model_review.rb} +8 -11
  26. data/lib/rails_best_practices/{checks/needless_deep_nesting_check.rb → reviews/needless_deep_nesting_review.rb} +8 -11
  27. data/lib/rails_best_practices/{checks/not_use_default_route_check.rb → reviews/not_use_default_route_review.rb} +7 -10
  28. data/lib/rails_best_practices/{checks/overuse_route_customizations_check.rb → reviews/overuse_route_customizations_review.rb} +10 -13
  29. data/lib/rails_best_practices/{checks/replace_complex_creation_with_factory_method_check.rb → reviews/replace_complex_creation_with_factory_method_review.rb} +8 -11
  30. data/lib/rails_best_practices/{checks/replace_instance_variable_with_local_variable_check.rb → reviews/replace_instance_variable_with_local_variable_review.rb} +7 -10
  31. data/lib/rails_best_practices/reviews/review.rb +92 -0
  32. data/lib/rails_best_practices/{checks/use_before_filter_check.rb → reviews/use_before_filter_review.rb} +8 -11
  33. data/lib/rails_best_practices/{checks/use_model_association_check.rb → reviews/use_model_association_review.rb} +8 -11
  34. data/lib/rails_best_practices/{checks/use_observer_check.rb → reviews/use_observer_review.rb} +14 -41
  35. data/lib/rails_best_practices/{checks/use_query_attribute_check.rb → reviews/use_query_attribute_review.rb} +20 -16
  36. data/lib/rails_best_practices/{checks/use_say_with_time_in_migrations_check.rb → reviews/use_say_with_time_in_migrations_review.rb} +8 -11
  37. data/lib/rails_best_practices/{checks/use_scope_access_check.rb → reviews/use_scope_access_review.rb} +8 -11
  38. data/lib/rails_best_practices/version.rb +1 -1
  39. data/rails_best_practices.gemspec +3 -2
  40. data/rails_best_practices.yml +22 -22
  41. data/rake_rubies.sh +3 -2
  42. data/spec/rails_best_practices/core/check_spec.rb +41 -0
  43. data/spec/rails_best_practices/core/checking_visitor_spec.rb +78 -0
  44. data/spec/rails_best_practices/core/visitable_sexp_spec.rb +39 -36
  45. data/spec/rails_best_practices/prepares/mailer_prepare_spec.rb +14 -0
  46. data/spec/rails_best_practices/prepares/model_prepare_spec.rb +22 -0
  47. data/spec/rails_best_practices/{checks/add_model_virtual_attribute_check_spec.rb → reviews/add_model_virtual_attribute_review_spec.rb} +17 -25
  48. data/spec/rails_best_practices/{checks/always_add_db_index_check_spec.rb → reviews/always_add_db_index_review_spec.rb} +28 -41
  49. data/spec/rails_best_practices/{checks/dry_bundler_in_capistrano_check_spec.rb → reviews/dry_bundler_in_capistrano_review_spec.rb} +7 -11
  50. data/spec/rails_best_practices/{checks/isolate_seed_data_check_spec.rb → reviews/isolate_seed_data_review_spec.rb} +13 -20
  51. data/spec/rails_best_practices/{checks/keep_finders_on_their_own_model_check_spec.rb → reviews/keep_finders_on_their_own_model_review_spec.rb} +16 -24
  52. data/spec/rails_best_practices/{checks/law_of_demeter_check_spec.rb → reviews/law_of_demeter_review_spec.rb} +24 -26
  53. data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +29 -0
  54. data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +24 -0
  55. data/spec/rails_best_practices/{checks/move_code_into_model_check_spec.rb → reviews/move_code_into_model_review_spec.rb} +12 -18
  56. data/spec/rails_best_practices/{checks/move_finder_to_named_scope_check_spec.rb → reviews/move_finder_to_named_scope_review_spec.rb} +12 -16
  57. data/spec/rails_best_practices/{checks/move_model_logic_into_model_check_spec.rb → reviews/move_model_logic_into_model_review_spec.rb} +7 -11
  58. data/spec/rails_best_practices/{checks/needless_deep_nesting_check_spec.rb → reviews/needless_deep_nesting_review_spec.rb} +26 -37
  59. data/spec/rails_best_practices/{checks/not_use_default_route_check_spec.rb → reviews/not_use_default_route_review_spec.rb} +13 -19
  60. data/spec/rails_best_practices/{checks/overuse_route_customizations_check_spec.rb → reviews/overuse_route_customizations_review_spec.rb} +27 -39
  61. data/spec/rails_best_practices/{checks/replace_complex_creation_with_factory_method_check_spec.rb → reviews/replace_complex_creation_with_factory_method_review_spec.rb} +10 -15
  62. data/spec/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review_spec.rb +31 -0
  63. data/spec/rails_best_practices/reviews/review_spec.rb +11 -0
  64. data/spec/rails_best_practices/{checks/use_before_filter_check_spec.rb → reviews/use_before_filter_review_spec.rb} +11 -17
  65. data/spec/rails_best_practices/{checks/use_model_association_check_spec.rb → reviews/use_model_association_review_spec.rb} +12 -18
  66. data/spec/rails_best_practices/{checks/use_observer_check_spec.rb → reviews/use_observer_review_spec.rb} +28 -29
  67. data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +190 -0
  68. data/spec/rails_best_practices/{checks/use_say_with_time_in_migrations_check_spec.rb → reviews/use_say_with_time_in_migrations_review_spec.rb} +14 -23
  69. data/spec/rails_best_practices/{checks/use_scope_access_check_spec.rb → reviews/use_scope_access_review_spec.rb} +28 -37
  70. data/spec/rails_best_practices_spec.rb +4 -4
  71. data/spec/spec_helper.rb +1 -0
  72. metadata +128 -102
  73. data/lib/rails_best_practices/checks.rb +0 -23
  74. data/lib/rails_best_practices/checks/check.rb +0 -203
  75. data/spec/rails_best_practices/checks/check_spec.rb +0 -57
  76. data/spec/rails_best_practices/checks/move_code_into_controller_check_spec.rb +0 -33
  77. data/spec/rails_best_practices/checks/move_code_into_helper_check_spec.rb +0 -28
  78. data/spec/rails_best_practices/checks/replace_instance_variable_with_local_variable_check_spec.rb +0 -36
  79. data/spec/rails_best_practices/checks/use_query_attribute_check_spec.rb +0 -192
data/Gemfile CHANGED
@@ -1,3 +1,2 @@
1
1
  source "http://rubygems.org"
2
- gem 'rake'
3
2
  gemspec
data/README.md CHANGED
@@ -62,6 +62,10 @@ Install
62
62
  Issue
63
63
  -----
64
64
 
65
+ If you install the rails_best_practices with bundler-installed github-sourced gem, please use the following command instead.
66
+
67
+ bundle exec rails_best_practices .
68
+
65
69
  If you got NoMethodError or any syntax error, you should use debug mode to detect which file rails_best_practices is parsing and getting the error.
66
70
 
67
71
  rails_best_practices -d .
@@ -79,30 +83,30 @@ to generate `rails_best_practices.yml` file.
79
83
 
80
84
  Now you can customize this configuration file, the default configuration is as follows:
81
85
 
82
- MoveFinderToNamedScopeCheck: { }
83
- UseModelAssociationCheck: { }
84
- UseScopeAccessCheck: { }
85
- AddModelVirtualAttributeCheck: { }
86
- ReplaceComplexCreationWithFactoryMethodCheck: { attribute_assignment_count: 2 }
87
- MoveModelLogicIntoModelCheck: { use_count: 4 }
88
- OveruseRouteCustomizationsCheck: { customize_count: 3 }
89
- NeedlessDeepNestingCheck: { nested_count: 2 }
90
- NotUseDefaultRouteCheck: { }
91
- KeepFindersOnTheirOwnModelCheck: { }
92
- LawOfDemeterCheck: { }
93
- UseObserverCheck: { }
94
- IsolateSeedDataCheck: { }
95
- AlwaysAddDbIndexCheck: { }
96
- UseBeforeFilterCheck: { }
97
- MoveCodeIntoControllerCheck: { }
98
- MoveCodeIntoModelCheck: { use_count: 2 }
99
- MoveCodeIntoHelperCheck: { array_count: 3 }
100
- ReplaceInstanceVariableWithLocalVariableCheck: { }
101
- DryBundlerInCapistranoCheck: { }
102
- UseSayWithTimeInMigrationsCheck: { }
103
- UseQueryAttributeCheck: { }
104
-
105
- You can remove or comment one check to disable it, and you can change the options.
86
+ MoveFinderToNamedScopeReview: { }
87
+ UseModelAssociationReview: { }
88
+ UseScopeAccessReview: { }
89
+ AddModelVirtualAttributeReview: { }
90
+ ReplaceComplexCreationWithFactoryMethodReview: { attribute_assignment_count: 2 }
91
+ MoveModelLogicIntoModelReview: { use_count: 4 }
92
+ OveruseRouteCustomizationsReview: { customize_count: 3 }
93
+ NeedlessDeepNestingReview: { nested_count: 2 }
94
+ NotUseDefaultRouteReview: { }
95
+ KeepFindersOnTheirOwnModelReview: { }
96
+ LawOfDemeterReview: { }
97
+ UseObserverReview: { }
98
+ IsolateSeedDataReview: { }
99
+ AlwaysAddDbIndexReview: { }
100
+ UseBeforeFilterReview: { }
101
+ MoveCodeIntoControllerReview: { }
102
+ MoveCodeIntoModelReview: { use_count: 2 }
103
+ MoveCodeIntoHelperReview: { array_count: 3 }
104
+ ReplaceInstanceVariableWithLocalVariableReview: { }
105
+ DryBundlerInCapistranoReview: { }
106
+ UseSayWithTimeInMigrationsReview: { }
107
+ UseQueryAttributeReview: { }
108
+
109
+ You can remove or comment one review to disable it, and you can change the options.
106
110
 
107
111
  Implementation
108
112
  --------------
data/Rakefile CHANGED
@@ -2,7 +2,6 @@ require "bundler"
2
2
  Bundler.setup
3
3
 
4
4
  require "rake"
5
- require "rake/rdoctask"
6
5
  require "rspec"
7
6
  require "rspec/core/rake_task"
8
7
 
@@ -35,11 +34,4 @@ Rspec::Core::RakeTask.new('spec:progress') do |spec|
35
34
  spec.pattern = "spec/**/*_spec.rb"
36
35
  end
37
36
 
38
- Rake::RDocTask.new do |rdoc|
39
- rdoc.rdoc_dir = "rdoc"
40
- rdoc.title = "rails_best_practices #{RailsBestPractices::VERSION}"
41
- rdoc.rdoc_files.include("README*")
42
- rdoc.rdoc_files.include("lib/**/*.rb")
43
- end
44
-
45
37
  task :default => :spec
@@ -2,7 +2,6 @@
2
2
  rubies=( 1.8.7 1.9.2 ree )
3
3
  for x in ${rubies[*]}
4
4
  do
5
- rvm install $x || exit $?
6
- rvm $x && rvm gemset use global && gem install bundler || exit $?
7
- bundle install || exit $?
5
+ rvm install $x
6
+ rvm $x && rvm gemset use global && gem install bundler
8
7
  done
@@ -26,7 +26,8 @@ require 'rubygems'
26
26
  require 'progressbar'
27
27
  require 'colored'
28
28
  require 'haml'
29
- require 'rails_best_practices/checks'
29
+ require 'rails_best_practices/prepares'
30
+ require 'rails_best_practices/reviews'
30
31
  require 'rails_best_practices/core'
31
32
  require 'fileutils'
32
33
 
@@ -73,9 +74,9 @@ module RailsBestPractices
73
74
  @runner.debug = true if @options['debug']
74
75
  @runner.color = !options['without-color']
75
76
 
76
- if @runner.checks.find { |check| check.is_a? Checks::AlwaysAddDbIndexCheck } &&
77
+ if @runner.checks.find { |check| check.is_a? Reviews::AlwaysAddDbIndexReview } &&
77
78
  !review_files.find { |file| file.index "db\/schema.rb" }
78
- plain_output("AlwaysAddDbIndexCheck is disabled as there is no db/schema.rb file in your rails project.", 'blue')
79
+ plain_output("AlwaysAddDbIndexReview is disabled as there is no db/schema.rb file in your rails project.", 'blue')
79
80
  end
80
81
 
81
82
  @bar = ProgressBar.new('Analyzing', prepare_files.size + review_files.size)
@@ -162,13 +163,13 @@ module RailsBestPractices
162
163
  # @return [Array] sorted files
163
164
  def file_sort files
164
165
  files.sort { |a, b|
165
- if a =~ Checks::Check::MODEL_FILES
166
+ if a =~ Core::Check::MODEL_FILES
166
167
  -1
167
- elsif b =~ Checks::Check::MODEL_FILES
168
+ elsif b =~ Core::Check::MODEL_FILES
168
169
  1
169
- elsif a =~ Checks::Check::MAILER_FILES
170
+ elsif a =~ Core::Check::MAILER_FILES
170
171
  -1
171
- elsif b =~ Checks::Check::MAILER_FILES
172
+ elsif b =~ Core::Check::MAILER_FILES
172
173
  1
173
174
  else
174
175
  a <=> b
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ require 'rails_best_practices/core/check'
2
3
  require 'rails_best_practices/core/runner'
3
4
  require 'rails_best_practices/core/checking_visitor'
4
5
  require 'rails_best_practices/core/error'
@@ -0,0 +1,68 @@
1
+ # encoding: utf-8
2
+ module RailsBestPractices
3
+ module Core
4
+ # A Check class that takes charge of checking the sexp.
5
+ class Check
6
+ # only nodes whose node_type is in NODE_TYPE will be reviewed.
7
+ NODE_TYPES = [:call, :defn, :defs, :if, :class, :lasgn, :iasgn, :ivar, :lvar, :block, :iter, :const]
8
+
9
+ CONTROLLER_FILES = /_controller\.rb$/
10
+ MIGRATION_FILES = /db\/migrate\/.*\.rb$/
11
+ MODEL_FILES = /models\/.*\.rb$/
12
+ MAILER_FILES = /models\/.*\.rb$|mailers\/.*\.rb/
13
+ VIEW_FILES = /views\/.*\.(erb|haml)$/
14
+ PARTIAL_VIEW_FILES = /views\/.*\/_.*\.(erb|haml)$/
15
+ ROUTE_FILE = /config\/routes.rb/
16
+
17
+ # default interesting nodes.
18
+ def interesting_nodes
19
+ []
20
+ end
21
+
22
+ # default interesting files.
23
+ def interesting_files
24
+ /.*/
25
+ end
26
+
27
+ # delegate to start_### according to the node_type, like
28
+ #
29
+ # start_call
30
+ # start_defn
31
+ #
32
+ # @param [Sexp] node
33
+ def node_start(node)
34
+ @node = node
35
+ self.send("start_#{node.node_type}", node)
36
+ end
37
+
38
+ # delegate to end_### according to the node_type, like
39
+ #
40
+ # end_call
41
+ # end_defn
42
+ #
43
+ # @param [Sexp] node
44
+ def node_end(node)
45
+ @node = node
46
+ self.send("end_#{node.node_type}", node)
47
+ end
48
+
49
+ # method_missing to catch all start and end process for each node type, like
50
+ #
51
+ # start_defn
52
+ # end_defn
53
+ # start_call
54
+ # end_call
55
+ #
56
+ # if there is a "debug" method defined in check, each node will be output.
57
+ def method_missing(method_name, *args)
58
+ if method_name.to_s =~ /^start_/
59
+ p args if respond_to?(:debug)
60
+ elsif method_name.to_s =~ /^end_/
61
+ # nothing to do
62
+ else
63
+ super
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -14,26 +14,29 @@ module RailsBestPractices
14
14
  # if the node_type and the node filename match the interesting_review_nodes and interesting_review_files,
15
15
  # then run the reivew for that node.
16
16
  class CheckingVisitor
17
- # remember all the checks for prepare and review processes according to interesting_prepare_nodes and interesting_review_nodes,
18
- def initialize(checks)
17
+ # remember all the checks for prepare and review processes according to interesting_nodes.
18
+ #
19
+ # @param [Array] prepares
20
+ # @param [Array] reviews
21
+ def initialize(prepares, reviews)
19
22
  [:prepare, :review].each do |process|
20
23
  instance_variable_set("@#{process}_checks", {}) # @review_checks = {}
21
- checks.each do |check| # checks.each do |check|
22
- check.send("interesting_#{process}_nodes").each do |node| # check.interesting_review_nodes.each do |node|
23
- instance_variable_get("@#{process}_checks")[node] ||= [] # @review_checks[node] ||= []
24
- instance_variable_get("@#{process}_checks")[node] << check # @review_checks[node] << check
25
- instance_variable_get("@#{process}_checks")[node].uniq! # @review_checks[node].uniq!
26
- end # end
27
- end
24
+ eval("#{process}s").each do |check| # reviews.each do |check|
25
+ check.send("interesting_nodes").each do |node| # check.interesting_nodes.each do |node|
26
+ instance_variable_get("@#{process}_checks")[node] ||= [] # @review_checks[node] ||= []
27
+ instance_variable_get("@#{process}_checks")[node] << check # @review_checks[node] << check
28
+ instance_variable_get("@#{process}_checks")[node].uniq! # @review_checks[node].uniq!
29
+ end # end
30
+ end # end
28
31
  end
29
32
  end
30
33
 
31
34
  # for prepare process
32
- # if the node_type and the node filename match the interesting_prepare_nodes and interesting_prepare_files,
35
+ # if the node_type and the node filename match the interesting_nodes and interesting_files,
33
36
  # then run the prepare for that node.
34
37
  #
35
38
  # for review process
36
- # if the node_type and the node filename match the interesting_review_nodes and interesting_review_files,
39
+ # if the node_type and the node filename match the interesting_nodes and interesting_files,
37
40
  # then run the reivew for that node.
38
41
  [:prepare, :review].each do |process|
39
42
  class_eval <<-EOS
@@ -41,16 +44,16 @@ module RailsBestPractices
41
44
  checks = @#{process}_checks[node.node_type] # checks = @review_checks[node.node_type]
42
45
  if checks # if checks
43
46
  checks.each { |check| # checks.each { |check|
44
- if node.file =~ check.interesting_#{process}_files # if node.file =~ check.interesting_review_files
45
- check.#{process}_node_start(node) # check.review_node_start(node)
47
+ if node.file =~ check.interesting_files # if node.file =~ check.interesting_files
48
+ check.node_start(node) # check.node_start(node)
46
49
  end # end
47
50
  } # }
48
51
  end # end
49
52
  node.children.each {|sexp| sexp.#{process}(self)} # node.children.each {|sexp| sexp.review(self)}
50
53
  if checks # if checks
51
54
  checks.each { |check| # checks.each { |check|
52
- if node.file =~ check.interesting_#{process}_files # if node.file =~ check.interesting_review_files
53
- check.#{process}_node_end(node) # check.review_node_end(node)
55
+ if node.file =~ check.interesting_files # if node.file =~ check.interesting_files
56
+ check.node_end(node) # check.node_end(node)
54
57
  end # end
55
58
  } # }
56
59
  end # end
@@ -31,12 +31,19 @@ module RailsBestPractices
31
31
  @base_path || "."
32
32
  end
33
33
 
34
- def initialize(*checks)
34
+ # initialize the runner.
35
+ #
36
+ # @param [Hash] options pass the prepares and reviews.
37
+ def initialize(options={})
35
38
  custom_config = File.join(Runner.base_path, 'config/rails_best_practices.yml')
36
39
  @config = File.exists?(custom_config) ? custom_config : RailsBestPractices::DEFAULT_CONFIG
37
- @checks = checks unless checks.empty?
38
- @checks ||= load_checks
39
- @checker ||= CheckingVisitor.new(@checks)
40
+
41
+ prepares = Array(options[:prepares])
42
+ reviews = Array(options[:reviews])
43
+ @prepares = prepares.empty? ? load_prepares : prepares
44
+ @reviews = reviews.empty? ? load_reviews : reviews
45
+
46
+ @checker ||= CheckingVisitor.new(@prepares, @reviews)
40
47
  @debug = false
41
48
  end
42
49
 
@@ -60,13 +67,11 @@ module RailsBestPractices
60
67
  EOS
61
68
  end
62
69
 
63
- # get all errors from checks.
70
+ # get all errors from reviews.
64
71
  #
65
- # @return [Array] all errors from checks
72
+ # @return [Array] all errors from reviews
66
73
  def errors
67
- @checks ||= []
68
- all_errors = @checks.collect {|check| check.errors}
69
- all_errors.flatten
74
+ @reviews.collect {|review| review.errors}.flatten
70
75
  end
71
76
 
72
77
  private
@@ -106,12 +111,17 @@ module RailsBestPractices
106
111
  content
107
112
  end
108
113
 
109
- # load all checks according to configuration.
110
- def load_checks
114
+ # load all prepares.
115
+ def load_prepares
116
+ [RailsBestPractices::Prepares::ModelPrepare.new, RailsBestPractices::Prepares::MailerPrepare.new]
117
+ end
118
+
119
+ # load all reviews according to configuration.
120
+ def load_reviews
111
121
  check_objects = []
112
122
  checks = YAML.load_file @config
113
123
  checks.each do |check|
114
- klass = RailsBestPractices::Checks.const_get(check[0])
124
+ klass = RailsBestPractices::Reviews.const_get(check[0].gsub(/Check/, 'Review'))
115
125
  check_objects << (check[1].empty? ? klass.new : klass.new(check[1]))
116
126
  end
117
127
  check_objects
@@ -395,10 +395,14 @@ class Sexp
395
395
 
396
396
  # to_s for lvar, ivar, lit, const, array, hash, and colon2 node.
397
397
  #
398
+ # @param [Hash] options
399
+ # :remove_at remove the @ symbol for ivar.
398
400
  # @return [String] to_s
399
- def to_s
401
+ def to_s(options={})
400
402
  case node_type
401
- when :lvar, :ivar, :str, :lit, :const
403
+ when :ivar
404
+ options[:remove_at] ? self[1].to_s[1..-1] : self[1].to_s
405
+ when :lvar, :str, :lit, :const
402
406
  self[1].to_s
403
407
  when :array
404
408
  "[\"#{self.children.collect(&:to_s).join('", "')}\"]"
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+ require 'rails_best_practices/prepares/model_prepare'
3
+ require 'rails_best_practices/prepares/mailer_prepare'
4
+
5
+ module RailsBestPractices
6
+ module Prepares
7
+ class <<self
8
+ attr_accessor :model_associations, :mailer_names
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ require 'rails_best_practices/core/check'
3
+
4
+ module RailsBestPractices
5
+ module Prepares
6
+ # Remember the mailer names.
7
+ class MailerPrepare < Core::Check
8
+
9
+ def interesting_nodes
10
+ [:class]
11
+ end
12
+
13
+ def interesting_files
14
+ /#{MAILER_FILES}|#{MODEL_FILES}/
15
+ end
16
+
17
+ def initialize
18
+ @mailer_names = []
19
+ end
20
+
21
+ # check class node.
22
+ #
23
+ # if it is a subclass of ActionMailer::Base,
24
+ # then remember its class name.
25
+ def start_class(class_node)
26
+ if s(:colon2, s(:const, :ActionMailer), :Base) == class_node.base_class
27
+ @mailer_names << class_node.class_name
28
+ Prepares.mailer_names = @mailer_names
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ require 'rails_best_practices/core/check'
3
+
4
+ module RailsBestPractices
5
+ module Prepares
6
+ # Remember the model associations.
7
+ class ModelPrepare < Core::Check
8
+
9
+ def interesting_nodes
10
+ [:class, :call]
11
+ end
12
+
13
+ def interesting_files
14
+ MODEL_FILES
15
+ end
16
+
17
+ def initialize
18
+ @associations = {}
19
+ end
20
+
21
+ # check class node to remember the last class name.
22
+ def start_class(class_node)
23
+ @last_klazz = class_node.class_name.to_s
24
+ end
25
+
26
+ # assign @associations to Prepare.model_associations.
27
+ def end_class(class_node)
28
+ Prepares.model_associations = @associations
29
+ end
30
+
31
+ # check call node to remember all assoications.
32
+ #
33
+ # the remembered association names (@associations) are like
34
+ # {
35
+ # :Project=>{
36
+ # "categories"=>:has_and_belongs_to_many,
37
+ # "project_manager"=>:has_one,
38
+ # "portfolio"=>:belongs_to,
39
+ # "milestones=>:has_many"
40
+ # }
41
+ # }
42
+ def start_call(node)
43
+ remember_association(node) if association_methods.include? node.message
44
+ end
45
+
46
+ # remember associations, with class to association names.
47
+ def remember_association(association_node)
48
+ association_meta = association_node.message
49
+ association_name = association_node.arguments[1].to_s
50
+ @associations[@last_klazz] ||= {}
51
+ @associations[@last_klazz][association_name] = association_meta
52
+ end
53
+
54
+ # default rails association methods.
55
+ def association_methods
56
+ [:belongs_to, :has_one, :has_many, :has_and_belongs_to_many]
57
+ end
58
+ end
59
+ end
60
+ end