rails_best_practices 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile.lock +1 -1
- data/README.md +2 -0
- data/assets/result.html.erb +25 -2
- data/lib/rails_best_practices.rb +20 -9
- data/lib/rails_best_practices/core.rb +1 -0
- data/lib/rails_best_practices/core/check.rb +106 -25
- data/lib/rails_best_practices/core/controllers.rb +2 -1
- data/lib/rails_best_practices/core/error.rb +3 -2
- data/lib/rails_best_practices/core/klasses.rb +34 -0
- data/lib/rails_best_practices/core/mailers.rb +2 -1
- data/lib/rails_best_practices/core/methods.rb +113 -9
- data/lib/rails_best_practices/core/model_associations.rb +17 -0
- data/lib/rails_best_practices/core/model_attributes.rb +16 -0
- data/lib/rails_best_practices/core/models.rb +3 -2
- data/lib/rails_best_practices/core/nil.rb +9 -1
- data/lib/rails_best_practices/core/runner.rb +65 -26
- data/lib/rails_best_practices/core_ext/sexp.rb +57 -0
- data/lib/rails_best_practices/prepares.rb +12 -1
- data/lib/rails_best_practices/prepares/controller_prepare.rb +13 -8
- data/lib/rails_best_practices/prepares/mailer_prepare.rb +3 -3
- data/lib/rails_best_practices/prepares/model_prepare.rb +44 -16
- data/lib/rails_best_practices/reviews.rb +1 -0
- data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +5 -2
- data/lib/rails_best_practices/reviews/remove_unused_methods_in_models_review.rb +77 -0
- data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +2 -2
- data/lib/rails_best_practices/reviews/review.rb +1 -1
- data/lib/rails_best_practices/version.rb +1 -1
- data/rails_best_practices.yml +1 -0
- data/spec/fixtures/lib/rails_best_practices/plugins/reviews/not_use_rails_root_review.rb +11 -0
- data/spec/rails_best_practices/core/check_spec.rb +22 -0
- data/spec/rails_best_practices/core/controllers_spec.rb +1 -1
- data/spec/rails_best_practices/core/error_spec.rb +1 -1
- data/spec/rails_best_practices/core/klasses_spec.rb +12 -0
- data/spec/rails_best_practices/core/mailers_spec.rb +5 -0
- data/spec/rails_best_practices/core/methods_spec.rb +26 -4
- data/spec/rails_best_practices/core/models_spec.rb +2 -2
- data/spec/rails_best_practices/core/runner_spec.rb +13 -0
- data/spec/rails_best_practices/core_ext/sexp_spec.rb +26 -2
- data/spec/rails_best_practices/prepares/controller_prepare_spec.rb +72 -60
- data/spec/rails_best_practices/prepares/mailer_prepare_spec.rb +1 -1
- data/spec/rails_best_practices/prepares/model_prepare_spec.rb +150 -59
- data/spec/rails_best_practices/reviews/move_model_logic_into_model_review_spec.rb +20 -3
- data/spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb +14 -0
- data/spec/rails_best_practices/reviews/remove_unused_methods_in_models_review_spec.rb +387 -0
- metadata +15 -3
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -133,6 +133,7 @@ Now you can customize this configuration file, the default configuration is as f
|
|
133
133
|
RemoveEmptyHelpersCheck: {}
|
134
134
|
RemoveTabCheck: {}
|
135
135
|
RestrictAutoGeneratedRoutesCheck: { }
|
136
|
+
RemoveUnusedMethodsInModelsCheck: { except_methods: [] }
|
136
137
|
|
137
138
|
You can remove or comment one review to disable it, and you can change the options.
|
138
139
|
|
@@ -161,6 +162,7 @@ Model
|
|
161
162
|
2. the Law of Demeter
|
162
163
|
3. Use Observer
|
163
164
|
4. Use Query Attribute
|
165
|
+
5. Remove Unused Methods In Models (Experiment, not available by default configuration)
|
164
166
|
|
165
167
|
Mailer
|
166
168
|
|
data/assets/result.html.erb
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
<head>
|
4
4
|
<meta charset='UTF-8' />
|
5
5
|
<title>Output of rails_best_practices</title>
|
6
|
-
|
7
6
|
<style type="text/css">
|
8
7
|
body {
|
9
8
|
color: #333;
|
@@ -34,6 +33,10 @@
|
|
34
33
|
table tr:hover {
|
35
34
|
background-color: #FFFFC0;
|
36
35
|
}
|
36
|
+
ul li {
|
37
|
+
list-style: none;
|
38
|
+
display: none;
|
39
|
+
}
|
37
40
|
</style>
|
38
41
|
</head>
|
39
42
|
<body>
|
@@ -50,6 +53,11 @@
|
|
50
53
|
Found <%= @errors.size %> errors.
|
51
54
|
<% end %>
|
52
55
|
</h2>
|
56
|
+
<ul>
|
57
|
+
<% @error_types.each do |error_type| %>
|
58
|
+
<li><input type="checkbox" value="<%= error_type.split(':').last %>" /><%= error_type.split(':').last %></li>
|
59
|
+
<% end %>
|
60
|
+
</ul>
|
53
61
|
<table>
|
54
62
|
<tr>
|
55
63
|
<th>Filename</th>
|
@@ -57,7 +65,7 @@
|
|
57
65
|
<th>Warning Message</th>
|
58
66
|
</tr>
|
59
67
|
<% @errors.each do |error| %>
|
60
|
-
<tr>
|
68
|
+
<tr class="<%= error.type.split(':').last %>">
|
61
69
|
<td class='filename'>
|
62
70
|
<% if @textmate %>
|
63
71
|
<a href='txmt://open/?url=file://<%= File.expand_path(error.filename) %>&line=<%= error.line_number %>'><%= error.filename %></a>
|
@@ -74,5 +82,20 @@
|
|
74
82
|
</tr>
|
75
83
|
<% end %>
|
76
84
|
</table>
|
85
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
|
86
|
+
<script type="text/javascript">
|
87
|
+
$(function() {
|
88
|
+
$('ul li').show();
|
89
|
+
$('input[type=checkbox]').prop('checked', true).click(function() {
|
90
|
+
if ($(this).attr('checked')) {
|
91
|
+
$(this).prop('checked', true);
|
92
|
+
$('.'+$(this).val()).show();
|
93
|
+
} else {
|
94
|
+
$(this).prop('checked', false);
|
95
|
+
$('.'+$(this).val()).hide();
|
96
|
+
}
|
97
|
+
});
|
98
|
+
});
|
99
|
+
</script>
|
77
100
|
</body>
|
78
101
|
</html>
|
data/lib/rails_best_practices.rb
CHANGED
@@ -83,6 +83,7 @@ module RailsBestPractices
|
|
83
83
|
|
84
84
|
@bar = ProgressBar.new('Analyzing', lexical_files.size + prepare_files.size + review_files.size)
|
85
85
|
["lexical", "prepare", "review"].each { |process| send(:process, process) }
|
86
|
+
@runner.on_complete
|
86
87
|
@bar.finish
|
87
88
|
|
88
89
|
if @options['format'] == 'html'
|
@@ -202,7 +203,7 @@ module RailsBestPractices
|
|
202
203
|
files.reject { |file| file.index(pattern) }
|
203
204
|
end
|
204
205
|
|
205
|
-
# output errors
|
206
|
+
# output errors on terminal.
|
206
207
|
def output_terminal_errors
|
207
208
|
@runner.errors.each { |error| plain_output(error.to_s, 'red') }
|
208
209
|
plain_output("\nPlease go to http://rails-bestpractices.com to see more useful Rails Best Practices.", 'green')
|
@@ -213,6 +214,21 @@ module RailsBestPractices
|
|
213
214
|
end
|
214
215
|
end
|
215
216
|
|
217
|
+
# output errors with html format.
|
218
|
+
def output_html_errors
|
219
|
+
require 'erubis'
|
220
|
+
template = File.read(File.join(File.dirname(__FILE__), "..", "assets", "result.html.erb"))
|
221
|
+
|
222
|
+
File.open("rails_best_practices_output.html", "w+") do |file|
|
223
|
+
eruby = Erubis::Eruby.new(template)
|
224
|
+
file.puts eruby.evaluate(:errors => @runner.errors, :error_types => error_types, :textmate => @options["with-textmate"], :mvim => @options["with-mvim"])
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# plain output with color.
|
229
|
+
#
|
230
|
+
# @param [String] message to output
|
231
|
+
# @param [String] color
|
216
232
|
def plain_output(message, color)
|
217
233
|
if @options["without-color"]
|
218
234
|
puts message
|
@@ -221,14 +237,9 @@ module RailsBestPractices
|
|
221
237
|
end
|
222
238
|
end
|
223
239
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
File.open("rails_best_practices_output.html", "w+") do |file|
|
229
|
-
eruby = Erubis::Eruby.new(template)
|
230
|
-
file.puts eruby.evaluate(:errors => @runner.errors, :textmate => @options["with-textmate"], :mvim => @options["with-mvim"])
|
231
|
-
end
|
240
|
+
# unique error types.
|
241
|
+
def error_types
|
242
|
+
@runner.errors.map(&:type).uniq
|
232
243
|
end
|
233
244
|
end
|
234
245
|
end
|
@@ -4,6 +4,7 @@ require 'rails_best_practices/core/runner'
|
|
4
4
|
require 'rails_best_practices/core/checking_visitor'
|
5
5
|
require 'rails_best_practices/core/error'
|
6
6
|
require 'rails_best_practices/core/nil'
|
7
|
+
require 'rails_best_practices/core/klasses'
|
7
8
|
require 'rails_best_practices/core/models'
|
8
9
|
require 'rails_best_practices/core/model_associations'
|
9
10
|
require 'rails_best_practices/core/model_attributes'
|
@@ -3,6 +3,7 @@ module RailsBestPractices
|
|
3
3
|
module Core
|
4
4
|
# A Check class that takes charge of checking the sexp.
|
5
5
|
class Check
|
6
|
+
|
6
7
|
CONTROLLER_FILES = /controllers\/.*\.rb$/
|
7
8
|
MIGRATION_FILES = /db\/migrate\/.*\.rb$/
|
8
9
|
MODEL_FILES = /models\/.*\.rb$/
|
@@ -13,12 +14,6 @@ module RailsBestPractices
|
|
13
14
|
SCHEMA_FILE = /db\/schema\.rb/
|
14
15
|
HELPER_FILES = /helpers.*\.rb$/
|
15
16
|
|
16
|
-
attr_reader :errors
|
17
|
-
|
18
|
-
def initialize
|
19
|
-
@errors = []
|
20
|
-
end
|
21
|
-
|
22
17
|
# default interesting nodes.
|
23
18
|
def interesting_nodes
|
24
19
|
[]
|
@@ -37,6 +32,9 @@ module RailsBestPractices
|
|
37
32
|
# @param [Sexp] node
|
38
33
|
def node_start(node)
|
39
34
|
@node = node
|
35
|
+
Array(self.class.callbacks["start_#{node.sexp_type}"]).each do |callback|
|
36
|
+
self.instance_exec node, &callback
|
37
|
+
end
|
40
38
|
self.send("start_#{node.sexp_type}", node)
|
41
39
|
end
|
42
40
|
|
@@ -49,14 +47,23 @@ module RailsBestPractices
|
|
49
47
|
def node_end(node)
|
50
48
|
@node = node
|
51
49
|
self.send("end_#{node.sexp_type}", node)
|
50
|
+
Array(self.class.callbacks["end_#{node.sexp_type}"]).each do |callback|
|
51
|
+
self.instance_exec node, &callback
|
52
|
+
end
|
52
53
|
end
|
53
54
|
|
54
55
|
# add error if source code violates rails best practice.
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
|
59
|
-
|
56
|
+
#
|
57
|
+
# @param [String] message, is the string message for violation of the rails best practice
|
58
|
+
# @param [String] file, is the filename of source code
|
59
|
+
# @param [Integer] line, is the line number of the source code which is reviewing
|
60
|
+
def add_error(message, file = @node.file, line = @node.line)
|
61
|
+
errors << RailsBestPractices::Core::Error.new("#{file}", "#{line}", message, self.class.to_s, url)
|
62
|
+
end
|
63
|
+
|
64
|
+
# errors that vialote the rails best practices.
|
65
|
+
def errors
|
66
|
+
@errors ||= []
|
60
67
|
end
|
61
68
|
|
62
69
|
# default url is empty.
|
@@ -84,31 +91,105 @@ module RailsBestPractices
|
|
84
91
|
end
|
85
92
|
end
|
86
93
|
|
87
|
-
|
88
|
-
#
|
89
|
-
def
|
90
|
-
|
94
|
+
class <<self
|
95
|
+
# callbacks for start_xxx and end_xxx.
|
96
|
+
def callbacks
|
97
|
+
@callbacks ||= {}
|
91
98
|
end
|
92
99
|
|
93
|
-
#
|
94
|
-
|
95
|
-
|
100
|
+
# add a callback.
|
101
|
+
#
|
102
|
+
# @param [String] name, callback name, can be start_xxx or end_xxx
|
103
|
+
# @param [Proc] block, be executed when callbacks are called
|
104
|
+
def add_callback(name, &block)
|
105
|
+
callbacks[name] ||= []
|
106
|
+
callbacks[name] << block
|
96
107
|
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Helper to parse the class name.
|
111
|
+
module Klassable
|
112
|
+
def self.included(base)
|
113
|
+
base.class_eval do
|
114
|
+
# remember module name
|
115
|
+
add_callback "start_module" do |node|
|
116
|
+
modules << node.module_name.to_s
|
117
|
+
end
|
118
|
+
|
119
|
+
# end of the module.
|
120
|
+
add_callback "end_module" do |node|
|
121
|
+
modules.pop
|
122
|
+
end
|
97
123
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
124
|
+
# remember the class anem
|
125
|
+
add_callback "start_class" do |node|
|
126
|
+
@klass = Core::Klass.new(node.class_name.to_s, node.base_class.to_s, modules)
|
127
|
+
end
|
128
|
+
|
129
|
+
# end of the class
|
130
|
+
add_callback "end_class" do |node|
|
131
|
+
@klass = nil
|
132
|
+
end
|
105
133
|
end
|
106
134
|
end
|
107
135
|
|
136
|
+
# get the current class name.
|
137
|
+
def current_class_name
|
138
|
+
@klass.to_s
|
139
|
+
end
|
140
|
+
|
141
|
+
# get the current extend class name.
|
142
|
+
def current_extend_class_name
|
143
|
+
@klass.extend_class_name
|
144
|
+
end
|
145
|
+
|
146
|
+
# modules.
|
108
147
|
def modules
|
109
148
|
@moduels ||= []
|
110
149
|
end
|
111
150
|
end
|
151
|
+
|
152
|
+
# Helper to add callback after all files reviewed.
|
153
|
+
module Completeable
|
154
|
+
def self.included(base)
|
155
|
+
base.class_eval do
|
156
|
+
add_callback "end_class" do |node|
|
157
|
+
if "RailsBestPractices::Complete" == node.class_name.to_s
|
158
|
+
on_complete
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Helper to parse the access control.
|
166
|
+
module Accessable
|
167
|
+
def self.included(base)
|
168
|
+
base.class_eval do
|
169
|
+
# remember the current access control for methods.
|
170
|
+
add_callback "start_var_ref" do |node|
|
171
|
+
if %w(public protected private).include? node.to_s
|
172
|
+
@access_control = node.to_s
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# set access control to "public" by default.
|
177
|
+
add_callback "start_class" do |node|
|
178
|
+
@access_control = "public"
|
179
|
+
end
|
180
|
+
|
181
|
+
# set access control to "public" by default.
|
182
|
+
add_callback "start_module" do |node|
|
183
|
+
@access_control = "public"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# get the current acces control.
|
188
|
+
def current_access_control
|
189
|
+
@access_control
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
112
193
|
end
|
113
194
|
end
|
114
195
|
end
|
@@ -5,12 +5,13 @@ module RailsBestPractices
|
|
5
5
|
#
|
6
6
|
# it indicates the filenname, line number and error message for the violation.
|
7
7
|
class Error
|
8
|
-
attr_reader :filename, :line_number, :message, :url
|
8
|
+
attr_reader :filename, :line_number, :message, :type, :url
|
9
9
|
|
10
|
-
def initialize(filename, line_number, message, url = nil)
|
10
|
+
def initialize(filename, line_number, message, type, url = nil)
|
11
11
|
@filename = filename
|
12
12
|
@line_number = line_number
|
13
13
|
@message = message
|
14
|
+
@type = type
|
14
15
|
@url = url
|
15
16
|
end
|
16
17
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module RailsBestPractices
|
3
|
+
module Core
|
4
|
+
# Klass container.
|
5
|
+
class Klasses < Array
|
6
|
+
# If include the class.
|
7
|
+
#
|
8
|
+
# @param [String] class name
|
9
|
+
# @return [Boolean] include or not
|
10
|
+
def include?(class_name)
|
11
|
+
find { |klass| klass.to_s == class_name }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Class info includes clas name, extend class name and module names.
|
16
|
+
class Klass
|
17
|
+
attr_reader :class_name, :extend_class_name
|
18
|
+
|
19
|
+
def initialize(class_name, extend_class_name, modules)
|
20
|
+
@class_name = class_name
|
21
|
+
@extend_class_name = extend_class_name
|
22
|
+
@modules = modules.dup
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
if @modules.empty?
|
27
|
+
@class_name
|
28
|
+
else
|
29
|
+
@modules.map { |modu| "#{modu}::" }.join("") + @class_name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,24 +1,128 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module RailsBestPractices
|
3
3
|
module Core
|
4
|
+
# Method container.
|
4
5
|
class Methods
|
5
6
|
def initialize
|
6
7
|
@methods = {}
|
8
|
+
@possible_methods = {}
|
7
9
|
end
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
# Add a method.
|
12
|
+
#
|
13
|
+
# @param [String] class name
|
14
|
+
# @param [String] method name
|
15
|
+
# @param [Hash] method meta, file and line, {"file" => "app/models/post.rb", "line" => 5}
|
16
|
+
# @param [String] access control, public, protected or private
|
17
|
+
def add_method(class_name, method_name, meta={}, access_control="public")
|
18
|
+
return if class_name == ""
|
19
|
+
methods(class_name) << Method.new(class_name, method_name, access_control, meta)
|
20
|
+
if access_control == "public"
|
21
|
+
@possible_methods[method_name] = false
|
22
|
+
end
|
12
23
|
end
|
13
24
|
|
14
|
-
|
15
|
-
|
16
|
-
|
25
|
+
# Get methods of a class.
|
26
|
+
#
|
27
|
+
# @param [String] class name
|
28
|
+
# @param [String] access control
|
29
|
+
# @return [Array] all methods of a class for such access control, if access control is nil, return all public/protected/private methods
|
30
|
+
def get_methods(class_name, access_control=nil)
|
31
|
+
if access_control
|
32
|
+
methods(class_name).select { |method| method.access_control == access_control }
|
33
|
+
else
|
34
|
+
methods(class_name)
|
35
|
+
end
|
17
36
|
end
|
18
37
|
|
19
|
-
|
20
|
-
|
21
|
-
|
38
|
+
# If a class has a method.
|
39
|
+
#
|
40
|
+
# @param [String] class name
|
41
|
+
# @param [String] method name
|
42
|
+
# @param [String] access control
|
43
|
+
# @return [Boolean] has a method or not
|
44
|
+
def has_method?(class_name, method_name, access_control=nil)
|
45
|
+
if access_control
|
46
|
+
!!methods(class_name).find { |method| method.method_name == method_name && method.access_control == access_control }
|
47
|
+
else
|
48
|
+
!!methods(class_name).find { |method| method.method_name == method_name }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Mark parent class' method as used.
|
53
|
+
#
|
54
|
+
# @param [String] class name
|
55
|
+
# @param [String] method name
|
56
|
+
def mark_extend_class_method_used(class_name, method_name)
|
57
|
+
klass = Prepares.klasses.find { |klass| klass.to_s == class_name }
|
58
|
+
if klass && klass.extend_class_name
|
59
|
+
mark_extend_class_method_used(klass.extend_class_name, method_name)
|
60
|
+
method = get_method(klass.extend_class_name, method_name)
|
61
|
+
method.mark_used if method
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# remomber the method name, the method is probably be used for the class' public method.
|
66
|
+
#
|
67
|
+
# @param [String] method name
|
68
|
+
def possible_public_used(method_name)
|
69
|
+
@possible_methods[method_name] = true
|
70
|
+
end
|
71
|
+
|
72
|
+
# Get a method in a class.
|
73
|
+
#
|
74
|
+
# @param [String] class name
|
75
|
+
# @param [String] method name
|
76
|
+
# @param [String] access control
|
77
|
+
# @return [Method] Method object
|
78
|
+
def get_method(class_name, method_name, access_control=nil)
|
79
|
+
if access_control
|
80
|
+
methods(class_name).find { |method| method.method_name == method_name && method.access_control == access_control }
|
81
|
+
else
|
82
|
+
methods(class_name).find { |method| method.method_name == method_name }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Get all unused methods.
|
87
|
+
#
|
88
|
+
# @param [String] access control
|
89
|
+
# @return [Array] array of Method
|
90
|
+
def get_all_unused_methods(access_control=nil)
|
91
|
+
@methods.inject([]) { |unused_methods, (class_name, methods)|
|
92
|
+
unused_methods += if access_control
|
93
|
+
methods.select { |method| method.access_control == access_control && !method.used }
|
94
|
+
else
|
95
|
+
methods.select { |method| !method.used }
|
96
|
+
end
|
97
|
+
}.reject { |method| method.access_control == "public" && @possible_methods[method.method_name] }
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
# Methods of a class.
|
102
|
+
#
|
103
|
+
# @param [String] class name
|
104
|
+
# @return [Array] array of methods
|
105
|
+
def methods(class_name)
|
106
|
+
@methods[class_name] ||= []
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Method info includes class name, method name, access control, file, line, used.
|
111
|
+
class Method
|
112
|
+
attr_reader :access_control, :class_name, :method_name, :used, :file, :line
|
113
|
+
|
114
|
+
def initialize(class_name, method_name, access_control, meta)
|
115
|
+
@class_name = class_name
|
116
|
+
@method_name = method_name
|
117
|
+
@file = meta["file"]
|
118
|
+
@line = meta["line"]
|
119
|
+
@access_control = access_control
|
120
|
+
@used = false
|
121
|
+
end
|
122
|
+
|
123
|
+
# Mark this method as used.
|
124
|
+
def mark_used
|
125
|
+
@used = true
|
22
126
|
end
|
23
127
|
end
|
24
128
|
end
|