rails_best_practices 0.6.6 → 0.6.7

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