rails_best_practices 0.5.3 → 0.5.5

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.
data/README.textile CHANGED
@@ -14,7 +14,7 @@ rails_best_practices .
14
14
 
15
15
  notice the period at the end, it can be the relative or absolute path of your rails app.
16
16
 
17
- And default rails_best_practices will do parse codes in vendor, spec, test and stories directories. If you need, see the command options:
17
+ And default rails_best_practices will do parse codes in vendor, spec, test and features directories. If you need, see the command options:
18
18
 
19
19
  <pre><code>
20
20
  $ rails_best_practices -h
@@ -23,7 +23,7 @@ Usage: rails_best_practices [options]
23
23
  --vendor include vendor files
24
24
  --spec include spec files
25
25
  --test include test files
26
- --stories include stories files
26
+ --features include features files
27
27
  -x, --exclude PATTERNS Don't analyze files matching a pattern
28
28
  (comma-separated regexp list)
29
29
  -v, --version Show this version
@@ -32,7 +32,7 @@ Usage: rails_best_practices [options]
32
32
 
33
33
  *************************************************
34
34
 
35
- h2. Helpful links
35
+ h2. Resources
36
36
 
37
37
  Homepage: "http://rails-bestpractices.com":http://rails-bestpractices.com
38
38
  Repository: "http://github.com/flyerhzm/rails_best_practices":http://github.com/flyerhzm/rails_best_practices
@@ -3,23 +3,27 @@ require 'rails_best_practices/checks'
3
3
  require 'rails_best_practices/core'
4
4
 
5
5
  module RailsBestPractices
6
-
6
+
7
7
  class <<self
8
+ def prepare_files
9
+ expand_dirs_to_files 'app/models'
10
+ end
11
+
8
12
  def analyze_files(dir = '.', options = {})
9
13
  files = expand_dirs_to_files(dir)
10
14
  files = model_first_sort(files)
11
15
  ['vendor', 'spec', 'test', 'stories', 'features'].each do |pattern|
12
16
  files = ignore_files(files, "#{pattern}/") unless options[pattern]
13
17
  end
14
-
18
+
15
19
  # Exclude files based on exclude regexes if the option is set.
16
20
  for pattern in options[:exclude]
17
21
  files = ignore_files(files, pattern)
18
22
  end
19
-
23
+
20
24
  files
21
25
  end
22
-
26
+
23
27
  def expand_dirs_to_files *dirs
24
28
  extensions = ['rb', 'erb', 'haml', 'builder']
25
29
 
@@ -40,6 +40,7 @@ module RailsBestPractices
40
40
 
41
41
  def evaluate_end(node)
42
42
  if :iter == node.node_type && :call == node.subject.node_type && s(:colon2, s(:const, :ActiveRecord), :Schema) == node.subject.subject
43
+ remove_only_type_foreign_keys
43
44
  @foreign_keys.each do |table, foreign_key|
44
45
  table_node = @table_nodes[table]
45
46
  foreign_key.each do |column|
@@ -67,16 +68,27 @@ module RailsBestPractices
67
68
 
68
69
  def add_foreign_key_column(table_name, foreign_key_column)
69
70
  @foreign_keys[table_name] ||= []
70
- if foreign_key_column =~ /_id$/
71
- unless @foreign_keys[table_name].find { |foreign_key| foreign_key.include? foreign_key_column }
71
+ if foreign_key_column =~ /(.*?)_id$/
72
+ if @foreign_keys[table_name].delete("#{$1}_type")
73
+ @foreign_keys[table_name] << ["#{$1}_id", "#{$1}_type"]
74
+ else
72
75
  @foreign_keys[table_name] << foreign_key_column
73
76
  end
74
77
  elsif foreign_key_column =~ /(.*?)_type$/
75
- @foreign_keys[table_name].delete("#{$1}_id")
76
- @foreign_keys[table_name] << ["#{$1}_id", foreign_key_column]
78
+ if @foreign_keys[table_name].delete("#{$1}_id")
79
+ @foreign_keys[table_name] << ["#{$1}_id", "#{$1}_type"]
80
+ else
81
+ @foreign_keys[table_name] << foreign_key_column
82
+ end
77
83
  end
78
84
  end
79
85
 
86
+ def remove_only_type_foreign_keys
87
+ @foreign_keys.delete_if { |table, foreign_key|
88
+ foreign_key.size == 1 && foreign_key[0] =~ /_type$/
89
+ }
90
+ end
91
+
80
92
  def indexed?(table, column)
81
93
  index_columns = @index_columns[table]
82
94
  !index_columns || !index_columns.any? { |e| greater_than(Array(e), Array(column)) }
@@ -4,8 +4,8 @@ require 'rails_best_practices/core/error'
4
4
  module RailsBestPractices
5
5
  module Checks
6
6
  class Check
7
- NODE_TYPES = [:call, :defn, :defs, :if, :unless, :class, :lasgn, :iasgn, :ivar, :lvar, :block, :iter]
8
-
7
+ NODE_TYPES = [:call, :defn, :defs, :if, :unless, :class, :lasgn, :iasgn, :ivar, :lvar, :block, :iter, :const]
8
+
9
9
  CONTROLLER_FILES = /_controller\.rb$/
10
10
  MIGRATION_FILES = /db\/migrate\/.*\.rb$/
11
11
  MODLE_FILES = /models\/.*\.rb$/
@@ -17,50 +17,81 @@ module RailsBestPractices
17
17
  def initialize
18
18
  @errors = []
19
19
  end
20
-
20
+
21
21
  def interesting_files
22
22
  /.*/
23
23
  end
24
-
24
+
25
+ def interesting_prepare_files
26
+ /.*/
27
+ end
28
+
25
29
  NODE_TYPES.each do |node|
26
30
  start_node_method = "evaluate_start_#{node}"
27
31
  end_node_method = "evaluate_end_#{node}"
28
32
  define_method(start_node_method) { |node| } unless self.respond_to?(start_node_method)
29
33
  define_method(end_node_method) { |node| } unless self.respond_to?(end_node_method)
34
+
35
+ prepare_start_node_method = "prepare_start_#{node}"
36
+ prepare_end_node_method = "prepare_end_#{node}"
37
+ define_method(prepare_start_node_method) { |node| } unless self.respond_to?(prepare_start_node_method)
38
+ define_method(prepare_end_node_method) { |node| } unless self.respond_to?(prepare_end_node_method)
30
39
  end
31
40
 
32
41
  def position(offset = 0)
33
42
  "#{@line[2]}:#{@line[1] + offset}"
34
43
  end
35
-
44
+
45
+ def prepare_start(node)
46
+ end
47
+
48
+ def prepare_end(node)
49
+ end
50
+
36
51
  def evaluate_start(node)
37
52
  end
38
53
 
39
54
  def evaluate_end(node)
40
55
  end
41
56
 
57
+ def prepare_node(position, node)
58
+ @node = node
59
+ prepare_method = "prepare_#{position}_#{node.node_type}"
60
+ self.send(prepare_method, node)
61
+ end
62
+
42
63
  def evaluate_node(position, node)
43
64
  @node = node
44
65
  eval_method = "evaluate_#{position}_#{node.node_type}"
45
66
  self.send(eval_method, node)
46
67
  end
47
68
 
69
+ def prepare_node_start(node)
70
+ prepare_node(:start, node)
71
+ prepare_start(node)
72
+ end
73
+
74
+ def prepare_node_end(node)
75
+ prepare_node(:end, node)
76
+ prepare_end(node)
77
+ end
78
+
48
79
  def evaluate_node_start(node)
49
80
  evaluate_node(:start, node)
50
81
  evaluate_start(node)
51
82
  end
52
-
83
+
53
84
  def evaluate_node_end(node)
54
85
  evaluate_node(:end, node)
55
86
  evaluate_end(node)
56
87
  end
57
-
88
+
58
89
  def add_error(error, file = nil, line = nil)
59
90
  file ||= @node.file
60
91
  line ||= @node.line
61
92
  @errors << RailsBestPractices::Core::Error.new("#{file}", "#{line}", error)
62
93
  end
63
-
94
+
64
95
  def equal?(node, expected)
65
96
  node.to_s == expected or node.to_s == ':' + expected.to_s
66
97
  end
@@ -21,65 +21,70 @@ module RailsBestPractices
21
21
  [:if, :class, :call]
22
22
  end
23
23
 
24
+ def interesting_prepare_files
25
+ MODLE_FILES
26
+ end
27
+
24
28
  def initialize
25
29
  super
26
30
  @klazzes = []
27
31
  @associations = {}
28
32
  end
29
33
 
30
- def evaluate_start(node)
31
- case node.node_type
32
- when :class
33
- remember_klazz(node)
34
- when :call
35
- remember_association(node) if ASSOCIATION_METHODS.include? node.message
36
- when :if
37
- if node = query_attribute_node(node.conditional_statement)
38
- add_error "use query attribute", node.file, node.line
39
- end
40
- else
41
- end
34
+ def prepare_start_class(node)
35
+ remember_klazz(node)
42
36
  end
43
37
 
44
- private
38
+ def prepare_start_call(node)
39
+ remember_association(node) if ASSOCIATION_METHODS.include? node.message
40
+ end
45
41
 
46
- def remember_klazz(class_node)
47
- if class_node.file =~ MODLE_FILES
48
- @klazzes << class_node.subject
42
+ def evaluate_start_if(node)
43
+ if node = query_attribute_node(node.conditional_statement)
44
+ subject_node = node.subject
45
+ add_error "use query attribute (#{subject_node.subject}.#{subject_node.message}?)", node.file, node.line
49
46
  end
50
47
  end
51
48
 
52
- def remember_association(association_node)
53
- @associations[@klazzes.last] ||= []
54
- @associations[@klazzes.last] << association_node.arguments[1].to_s
55
- end
49
+ private
50
+ def remember_klazz(class_node)
51
+ if class_node.file =~ MODLE_FILES
52
+ @klazzes << class_node.subject
53
+ end
54
+ end
56
55
 
57
- def query_attribute_node(conditional_statement_node)
58
- case conditional_statement_node.node_type
59
- when :and, :or
60
- return query_attribute_node(conditional_statement_node[1]) || query_attribute_node(conditional_statement_node[2])
61
- when :not
62
- return query_attribute_node(conditional_statement_node[1])
63
- when :call
64
- return conditional_statement_node if query_method?(conditional_statement_node) or compare_with_empty_string?(conditional_statement_node)
56
+ def remember_association(association_node)
57
+ @associations[@klazzes.last] ||= []
58
+ @associations[@klazzes.last] << association_node.arguments[1].to_s
65
59
  end
66
- nil
67
- end
68
60
 
69
- def query_method?(node)
70
- return false unless :call == node.subject.node_type
71
- subject = node.subject.subject
72
- message = node.subject.message
73
- subject_ruby = subject.to_s
61
+ def query_attribute_node(conditional_statement_node)
62
+ case conditional_statement_node.node_type
63
+ when :and, :or
64
+ return query_attribute_node(conditional_statement_node[1]) || query_attribute_node(conditional_statement_node[2])
65
+ when :not
66
+ return query_attribute_node(conditional_statement_node[1])
67
+ when :call
68
+ return conditional_statement_node if query_method?(conditional_statement_node) or compare_with_empty_string?(conditional_statement_node)
69
+ end
70
+ nil
71
+ end
74
72
 
75
- subject_ruby && @klazzes.find { |klazz| subject_ruby =~ %r|#{klazz.to_s.underscore}| and !@associations[klazz].find { |association| equal?(association, message) } } &&
76
- message && message.to_s.pluralize != message.to_s &&
77
- QUERY_METHODS.include?(node.message)
78
- end
73
+ def query_method?(node)
74
+ return false unless :call == node.subject.node_type
75
+ subject = node.subject.subject
76
+ message = node.subject.message
77
+ subject_ruby = subject.to_s
79
78
 
80
- def compare_with_empty_string?(node)
81
- :== == node.message and [:arglist, [:str, ""]] == node.arguments
82
- end
79
+ subject_ruby && node.subject.arguments.size == 1 &&
80
+ @klazzes.find { |klazz| subject_ruby =~ %r|#{klazz.to_s.underscore}| and !@associations[klazz].find { |association| equal?(association, message) } } &&
81
+ message && message.to_s.pluralize != message.to_s &&
82
+ QUERY_METHODS.include?(node.message)
83
+ end
84
+
85
+ def compare_with_empty_string?(node)
86
+ :== == node.message and [:arglist, [:str, ""]] == node.arguments
87
+ end
83
88
  end
84
89
  end
85
90
  end
@@ -11,7 +11,7 @@ OptionParser.new do |opts|
11
11
  options['debug'] = true
12
12
  end
13
13
 
14
- ['vendor', 'spec', 'test', 'stories'].each do |pattern|
14
+ ['vendor', 'spec', 'test', 'features'].each do |pattern|
15
15
  opts.on("--#{pattern}", "include #{pattern} files") do
16
16
  options[pattern] = true
17
17
  end
@@ -42,6 +42,7 @@ end
42
42
  runner = RailsBestPractices::Core::Runner.new
43
43
  runner.set_debug if options['debug']
44
44
 
45
+ prepare_files = RailsBestPractices::prepare_files
45
46
  files = RailsBestPractices::analyze_files(ARGV, options)
46
47
 
47
48
  if runner.checks.find { |check| check.is_a? RailsBestPractices::Checks::AlwaysAddDbIndexCheck } &&
@@ -49,7 +50,13 @@ if runner.checks.find { |check| check.is_a? RailsBestPractices::Checks::AlwaysAd
49
50
  puts "AlwaysAddDbIndexCheck is disabled as there is no db/schema.rb file in your rails project.".blue
50
51
  end
51
52
 
52
- bar = ProgressBar.new('Analyzing', files.size)
53
+ bar = ProgressBar.new('Analyzing', prepare_files.size + files.size)
54
+
55
+ prepare_files.each do |file|
56
+ runner.prepare_file(file)
57
+ bar.inc unless options['debug']
58
+ end
59
+
53
60
  files.each do |file|
54
61
  runner.check_file(file)
55
62
  bar.inc unless options['debug']
@@ -14,12 +14,17 @@ module RailsBestPractices
14
14
  end
15
15
  end
16
16
 
17
+ def prepare(node)
18
+ checks = @checks[node.node_type]
19
+ checks.each {|check| check.prepare_node_start(node) if node.file =~ check.interesting_prepare_files} unless checks.nil?
20
+ node.visitable_children.each {|sexp| sexp.prepare(self)}
21
+ checks.each {|check| check.prepare_node_end(node) if node.file =~ check.interesting_prepare_files} unless checks.nil?
22
+ end
23
+
17
24
  def visit(node)
18
25
  checks = @checks[node.node_type]
19
26
  checks.each {|check| check.evaluate_node_start(node) if node.file =~ check.interesting_files} unless checks.nil?
20
-
21
27
  node.visitable_children.each {|sexp| sexp.accept(self)}
22
-
23
28
  checks.each {|check| check.evaluate_node_end(node) if node.file =~ check.interesting_files} unless checks.nil?
24
29
  end
25
30
  end
@@ -27,30 +27,25 @@ module RailsBestPractices
27
27
 
28
28
  def check(filename, content)
29
29
  puts filename if @debug
30
- if filename =~ /.*\.erb$/
31
- content = Erubis::Eruby.new(content).src
32
- end
33
- if filename =~ /.*\.haml$/
34
- begin
35
- require 'haml'
36
- content = Haml::Engine.new(content).precompiled
37
- # remove \xxx characters
38
- content.gsub!(/\\\d{3}/, '')
39
- rescue Haml::SyntaxError
40
- end
41
- end
42
- node = parse(filename, content)
30
+ content = parse_erb_or_haml(filename, content)
31
+ node = parse_ruby(filename, content)
43
32
  node.accept(@checker) if node
44
33
  end
45
34
 
46
- def check_content(content)
47
- check("dummy-file.rb", content)
35
+ def prepare(filename, content)
36
+ puts filename if @debug
37
+ node = parse_ruby(filename, content)
38
+ node.prepare(@checker) if node
48
39
  end
49
40
 
50
41
  def check_file(filename)
51
42
  check(filename, File.read(filename))
52
43
  end
53
44
 
45
+ def prepare_file(filename)
46
+ prepare(filename, File.read(filename))
47
+ end
48
+
54
49
  def errors
55
50
  @checks ||= []
56
51
  all_errors = @checks.collect {|check| check.errors}
@@ -59,7 +54,7 @@ module RailsBestPractices
59
54
 
60
55
  private
61
56
 
62
- def parse(filename, content)
57
+ def parse_ruby(filename, content)
63
58
  begin
64
59
  RubyParser.new.parse(content, filename)
65
60
  rescue Exception => e
@@ -68,6 +63,22 @@ module RailsBestPractices
68
63
  end
69
64
  end
70
65
 
66
+ def parse_erb_or_haml(filename, content)
67
+ if filename =~ /.*\.erb$/
68
+ content = Erubis::Eruby.new(content).src
69
+ end
70
+ if filename =~ /.*\.haml$/
71
+ begin
72
+ require 'haml'
73
+ content = Haml::Engine.new(content).precompiled
74
+ # remove \xxx characters
75
+ content.gsub!(/\\\d{3}/, '')
76
+ rescue Haml::SyntaxError
77
+ end
78
+ end
79
+ content
80
+ end
81
+
71
82
  def load_checks
72
83
  check_objects = []
73
84
  checks = YAML.load_file @config
@@ -3,6 +3,10 @@ require 'rubygems'
3
3
  require 'sexp'
4
4
 
5
5
  class Sexp
6
+ def prepare(visitor)
7
+ visitor.prepare(self)
8
+ end
9
+
6
10
  def accept(visitor)
7
11
  visitor.visit(self)
8
12
  end
@@ -14,23 +18,23 @@ class Sexp
14
18
  def children
15
19
  find_all { | sexp | Sexp === sexp }
16
20
  end
17
-
21
+
18
22
  def is_language_node?
19
23
  first.class == Symbol
20
24
  end
21
-
25
+
22
26
  def visitable_children
23
27
  parent = is_language_node? ? sexp_body : self
24
28
  parent.children
25
29
  end
26
-
30
+
27
31
  def recursive_children(&handler)
28
32
  visitable_children.each do |child|
29
33
  handler.call child
30
34
  child.recursive_children(&handler)
31
35
  end
32
36
  end
33
-
37
+
34
38
  def grep_nodes(options)
35
39
  return self if options.empty?
36
40
  node_type = options[:node_type]
@@ -45,7 +49,7 @@ class Sexp
45
49
  end
46
50
  nodes
47
51
  end
48
-
52
+
49
53
  def subject
50
54
  if [:attrasgn, :call, :class, :iter].include? node_type
51
55
  self[1]
@@ -57,37 +61,37 @@ class Sexp
57
61
  self[1]
58
62
  end
59
63
  end
60
-
64
+
61
65
  def message
62
66
  if [:attrasgn, :call, :defs, :iter].include? node_type
63
67
  self[2]
64
68
  end
65
69
  end
66
-
70
+
67
71
  def arguments
68
72
  if [:attrasgn, :call].include? node_type
69
73
  self[3]
70
74
  end
71
75
  end
72
-
76
+
73
77
  def call
74
78
  if [:if, :arglist].include? node_type
75
79
  self[1]
76
80
  end
77
81
  end
78
-
82
+
79
83
  def conditional_statement
80
84
  if node_type == :if
81
85
  self[1]
82
86
  end
83
87
  end
84
-
88
+
85
89
  def true_node
86
90
  if :if == node_type
87
91
  self[2]
88
92
  end
89
93
  end
90
-
94
+
91
95
  def false_node
92
96
  if :if == node_type
93
97
  self[3]
@@ -99,7 +103,7 @@ class Sexp
99
103
  self[1]
100
104
  end
101
105
  end
102
-
106
+
103
107
  def body
104
108
  if :block == node_type
105
109
  self[1..-1]
@@ -111,7 +115,7 @@ class Sexp
111
115
  self[4][1]
112
116
  end
113
117
  end
114
-
118
+
115
119
  def to_s
116
120
  if [:lvar, :ivar].include? node_type
117
121
  self[1].to_s
@@ -119,6 +123,8 @@ class Sexp
119
123
  self[1]
120
124
  elsif :lit == node_type
121
125
  ":#{self[1]}"
126
+ elsif :const == node_type
127
+ self[1]
122
128
  elsif :array == node_type
123
129
  "[\"#{self.children.collect(&:to_s).join('", "')}\"]"
124
130
  elsif :hash == node_type
@@ -132,11 +138,11 @@ class Sexp
132
138
  result += "}"
133
139
  end
134
140
  end
135
-
141
+
136
142
  #def to_ruby
137
143
  #Ruby2Ruby.new.process(self) unless self.empty?
138
144
  #end
139
-
145
+
140
146
  #def to_ruby_string
141
147
  #return nil if self.empty?
142
148
  #eval(Ruby2Ruby.new.process(self)).to_s
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
  module RailsBestPractices
3
- VERSION = "0.5.3"
3
+ VERSION = "0.5.5"
4
4
  end
5
5
 
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_best_practices
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 1
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 5
8
- - 3
9
- version: 0.5.3
9
+ - 5
10
+ version: 0.5.5
10
11
  platform: ruby
11
12
  authors:
12
13
  - Richard Huang
@@ -14,138 +15,147 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-12-04 00:00:00 +08:00
18
+ date: 2010-12-13 00:00:00 +08:00
18
19
  default_executable: rails_best_practices
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
- name: ruby_parser
22
- requirement: &id001 !ruby/object:Gem::Requirement
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
23
  none: false
24
24
  requirements:
25
25
  - - ~>
26
26
  - !ruby/object:Gem::Version
27
+ hash: 7
27
28
  segments:
28
29
  - 2
29
30
  - 0
30
31
  - 4
31
32
  version: 2.0.4
32
- type: :runtime
33
+ requirement: *id001
34
+ name: ruby_parser
33
35
  prerelease: false
34
- version_requirements: *id001
36
+ type: :runtime
35
37
  - !ruby/object:Gem::Dependency
36
- name: progressbar
37
- requirement: &id002 !ruby/object:Gem::Requirement
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
38
39
  none: false
39
40
  requirements:
40
41
  - - ~>
41
42
  - !ruby/object:Gem::Version
43
+ hash: 59
42
44
  segments:
43
45
  - 0
44
46
  - 9
45
47
  - 0
46
48
  version: 0.9.0
47
- type: :runtime
49
+ requirement: *id002
50
+ name: progressbar
48
51
  prerelease: false
49
- version_requirements: *id002
52
+ type: :runtime
50
53
  - !ruby/object:Gem::Dependency
51
- name: colored
52
- requirement: &id003 !ruby/object:Gem::Requirement
54
+ version_requirements: &id003 !ruby/object:Gem::Requirement
53
55
  none: false
54
56
  requirements:
55
57
  - - ~>
56
58
  - !ruby/object:Gem::Version
59
+ hash: 11
57
60
  segments:
58
61
  - 1
59
62
  - 2
60
63
  version: "1.2"
61
- type: :runtime
64
+ requirement: *id003
65
+ name: colored
62
66
  prerelease: false
63
- version_requirements: *id003
67
+ type: :runtime
64
68
  - !ruby/object:Gem::Dependency
65
- name: erubis
66
- requirement: &id004 !ruby/object:Gem::Requirement
69
+ version_requirements: &id004 !ruby/object:Gem::Requirement
67
70
  none: false
68
71
  requirements:
69
72
  - - ~>
70
73
  - !ruby/object:Gem::Version
74
+ hash: 27
71
75
  segments:
72
76
  - 2
73
77
  - 6
74
78
  - 6
75
79
  version: 2.6.6
76
- type: :runtime
80
+ requirement: *id004
81
+ name: erubis
77
82
  prerelease: false
78
- version_requirements: *id004
83
+ type: :runtime
79
84
  - !ruby/object:Gem::Dependency
80
- name: i18n
81
- requirement: &id005 !ruby/object:Gem::Requirement
85
+ version_requirements: &id005 !ruby/object:Gem::Requirement
82
86
  none: false
83
87
  requirements:
84
88
  - - ">="
85
89
  - !ruby/object:Gem::Version
90
+ hash: 3
86
91
  segments:
87
92
  - 0
88
93
  version: "0"
89
- type: :runtime
94
+ requirement: *id005
95
+ name: i18n
90
96
  prerelease: false
91
- version_requirements: *id005
97
+ type: :runtime
92
98
  - !ruby/object:Gem::Dependency
93
- name: activesupport
94
- requirement: &id006 !ruby/object:Gem::Requirement
99
+ version_requirements: &id006 !ruby/object:Gem::Requirement
95
100
  none: false
96
101
  requirements:
97
102
  - - ">="
98
103
  - !ruby/object:Gem::Version
104
+ hash: 3
99
105
  segments:
100
106
  - 0
101
107
  version: "0"
102
- type: :runtime
108
+ requirement: *id006
109
+ name: activesupport
103
110
  prerelease: false
104
- version_requirements: *id006
111
+ type: :runtime
105
112
  - !ruby/object:Gem::Dependency
106
- name: rspec
107
- requirement: &id007 !ruby/object:Gem::Requirement
113
+ version_requirements: &id007 !ruby/object:Gem::Requirement
108
114
  none: false
109
115
  requirements:
110
116
  - - ~>
111
117
  - !ruby/object:Gem::Version
118
+ hash: 13
112
119
  segments:
113
120
  - 2
114
121
  - 0
115
122
  - 1
116
123
  version: 2.0.1
117
- type: :development
124
+ requirement: *id007
125
+ name: rspec
118
126
  prerelease: false
119
- version_requirements: *id007
127
+ type: :development
120
128
  - !ruby/object:Gem::Dependency
121
- name: haml
122
- requirement: &id008 !ruby/object:Gem::Requirement
129
+ version_requirements: &id008 !ruby/object:Gem::Requirement
123
130
  none: false
124
131
  requirements:
125
132
  - - ~>
126
133
  - !ruby/object:Gem::Version
134
+ hash: 35
127
135
  segments:
128
136
  - 3
129
137
  - 0
130
138
  - 18
131
139
  version: 3.0.18
132
- type: :development
140
+ requirement: *id008
141
+ name: haml
133
142
  prerelease: false
134
- version_requirements: *id008
143
+ type: :development
135
144
  - !ruby/object:Gem::Dependency
136
- name: watchr
137
- requirement: &id009 !ruby/object:Gem::Requirement
145
+ version_requirements: &id009 !ruby/object:Gem::Requirement
138
146
  none: false
139
147
  requirements:
140
148
  - - ~>
141
149
  - !ruby/object:Gem::Version
150
+ hash: 7
142
151
  segments:
143
152
  - 0
144
153
  - 6
145
154
  version: "0.6"
146
- type: :development
155
+ requirement: *id009
156
+ name: watchr
147
157
  prerelease: false
148
- version_requirements: *id009
158
+ type: :development
149
159
  description: a code metric tool for rails codes, written in Ruby.
150
160
  email:
151
161
  - flyerhzm@gmail.com
@@ -208,7 +218,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
208
218
  requirements:
209
219
  - - ">="
210
220
  - !ruby/object:Gem::Version
211
- hash: -3421555404989740069
221
+ hash: 3
212
222
  segments:
213
223
  - 0
214
224
  version: "0"
@@ -217,6 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
227
  requirements:
218
228
  - - ">="
219
229
  - !ruby/object:Gem::Version
230
+ hash: 23
220
231
  segments:
221
232
  - 1
222
233
  - 3