Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 313 lines (283 sloc) 9.719 kB
f28bd95 @jeremy Fix dependencies revealed by testing in isolation
jeremy authored
1 require 'active_support/inflector'
75a960c Don't act destructively on ActiveModel::Name#human options hash. [#53…
John Firebaugh authored
2 require 'active_support/core_ext/hash/except'
973b908 @snusnu Added missing AS require to active_model/naming.rb
snusnu authored
3 require 'active_support/core_ext/module/introspection'
f28bd95 @jeremy Fix dependencies revealed by testing in isolation
jeremy authored
4
1c4d28b @josh Move model naming into ActiveModel
josh authored
5 module ActiveModel
72cbccb ActiveModel::Name does not inherit from string
Lukasz Sarnacki authored
6 class Name
7 include Comparable
8
bf8d757 @nertzy Remove ActiveModel::Naming#partial_path
nertzy authored
9 attr_reader :singular, :plural, :element, :collection,
72cbccb ActiveModel::Name does not inherit from string
Lukasz Sarnacki authored
10 :singular_route_key, :route_key, :param_key, :i18n_key,
11 :name
7280787 @josevalim Improve cache on route_key lookup.
josevalim authored
12
99cf77b @jeremy Add #element and #collection to ModelName
jeremy authored
13 alias_method :cache_key, :collection
566d717 @jeremy Move Class::ModelName to Active Support module core_ext
jeremy authored
14
809d4f8 update ActiveModel::Name documentation [ci skip]
Francesco Rodriguez authored
15 ##
16 # :method: ==
17 #
18 # :call-seq:
19 # ==(other)
20 #
21 # Equivalent to <tt>String#==</tt>. Returns +true+ if the class name and
22 # +other+ are equal, otherwise +false+.
23 #
24 # class BlogPost
25 # extend ActiveModel::Naming
26 # end
27 #
28 # BlogPost.model_name == 'BlogPost' # => true
29 # BlogPost.model_name == 'Blog Post' # => false
30
31 ##
32 # :method: ===
33 #
34 # :call-seq:
35 # ===(other)
36 #
37 # Equivalent to <tt>#==</tt>.
38 #
39 # class BlogPost
40 # extend ActiveModel::Naming
41 # end
42 #
43 # BlogPost.model_name === 'BlogPost' # => true
44 # BlogPost.model_name === 'Blog Post' # => false
45
46 ##
47 # :method: <=>
48 #
49 # :call-seq:
50 # ==(other)
51 #
52 # Equivalent to <tt>String#<=></tt>.
53 #
54 # class BlogPost
55 # extend ActiveModel::Naming
56 # end
57 #
58 # BlogPost.model_name <=> 'BlogPost' # => 0
59 # BlogPost.model_name <=> 'Blog' # => 1
60 # BlogPost.model_name <=> 'BlogPosts' # => -1
61
62 ##
63 # :method: =~
64 #
65 # :call-seq:
66 # =~(regexp)
67 #
68 # Equivalent to <tt>String#=~</tt>. Match the class name against the given
69 # regexp. Returns the position where the match starts or +nil+ if there is
70 # no match.
71 #
72 # class BlogPost
73 # extend ActiveModel::Naming
74 # end
75 #
76 # BlogPost.model_name =~ /Post/ # => 4
77 # BlogPost.model_name =~ /\d/ # => nil
78
79 ##
80 # :method: !~
81 #
82 # :call-seq:
83 # !~(regexp)
84 #
85 # Equivalent to <tt>String#!~</tt>. Match the class name against the given
86 # regexp. Returns +true+ if there is no match, otherwise +false+.
87 #
88 # class BlogPost
89 # extend ActiveModel::Naming
90 # end
91 #
92 # BlogPost.model_name !~ /Post/ # => false
93 # BlogPost.model_name !~ /\d/ # => true
94
95 ##
96 # :method: eql?
97 #
98 # :call-seq:
99 # eql?(other)
100 #
101 # Equivalent to <tt>String#eql?</tt>. Returns +true+ if the class name and
102 # +other+ have the same length and content, otherwise +false+.
103 #
104 # class BlogPost
105 # extend ActiveModel::Naming
106 # end
107 #
108 # BlogPost.model_name.eql?('BlogPost') # => true
109 # BlogPost.model_name.eql?('Blog Post') # => false
110
111 ##
112 # :method: to_s
113 #
114 # :call-seq:
115 # to_s()
116 #
117 # Returns the class name.
118 #
119 # class BlogPost
120 # extend ActiveModel::Naming
121 # end
122 #
123 # BlogPost.model_name.to_s # => "BlogPost"
124
125 ##
126 # :method: to_str
127 #
128 # :call-seq:
129 # to_str()
130 #
131 # Equivalent to +to_s+.
72cbccb ActiveModel::Name does not inherit from string
Lukasz Sarnacki authored
132 delegate :==, :===, :<=>, :=~, :"!~", :eql?, :to_s,
133 :to_str, :to => :name
dc39af0 @qoobaa make ActiveModel::Name fail gracefully with anonymous classes
qoobaa authored
134
809d4f8 update ActiveModel::Name documentation [ci skip]
Francesco Rodriguez authored
135 # Returns a new ActiveModel::Name instance. By default, the +namespace+
136 # and +name+ option will take the namespace and name of the given class
137 # respectively.
138 #
139 # module Foo
140 # class Bar
141 # end
142 # end
143 #
144 # ActiveModel::Name.new(Foo::Bar).to_s
145 # # => "Foo::Bar"
72cbccb ActiveModel::Name does not inherit from string
Lukasz Sarnacki authored
146 def initialize(klass, namespace = nil, name = nil)
147 @name = name || klass.name
dc39af0 @qoobaa make ActiveModel::Name fail gracefully with anonymous classes
qoobaa authored
148
72cbccb ActiveModel::Name does not inherit from string
Lukasz Sarnacki authored
149 raise ArgumentError, "Class name cannot be blank. You need to supply a name argument when anonymous class given" if @name.blank?
6e5aed0 @drogus Prepared ActiveModel::Naming to handle cases for namespaced isolated …
drogus authored
150
72cbccb ActiveModel::Name does not inherit from string
Lukasz Sarnacki authored
151 @unnamespaced = @name.sub(/^#{namespace.name}::/, '') if namespace
fd86a1b @josevalim Rely on a public contract between railties instead of accessing railt…
josevalim authored
152 @klass = klass
65f4d80 @tenderlove no need to freeze things all the time
tenderlove authored
153 @singular = _singularize(@name)
154 @plural = ActiveSupport::Inflector.pluralize(@singular)
155 @element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(@name))
156 @human = ActiveSupport::Inflector.humanize(@element)
157 @collection = ActiveSupport::Inflector.tableize(@name)
158 @param_key = (namespace ? _singularize(@unnamespaced) : @singular)
72cbccb ActiveModel::Name does not inherit from string
Lukasz Sarnacki authored
159 @i18n_key = @name.underscore.to_sym
7280787 @josevalim Improve cache on route_key lookup.
josevalim authored
160
161 @route_key = (namespace ? ActiveSupport::Inflector.pluralize(@param_key) : @plural.dup)
65f4d80 @tenderlove no need to freeze things all the time
tenderlove authored
162 @singular_route_key = ActiveSupport::Inflector.singularize(@route_key)
7280787 @josevalim Improve cache on route_key lookup.
josevalim authored
163 @route_key << "_index" if @plural == @singular
566d717 @jeremy Move Class::ModelName to Active Support module core_ext
jeremy authored
164 end
e31077c @josevalim Small clean up in Naming and TTranslation tests.
josevalim authored
165
166 # Transform the model name into a more humane format, using I18n. By default,
809d4f8 update ActiveModel::Name documentation [ci skip]
Francesco Rodriguez authored
167 # it will underscore then humanize the class name.
168 #
169 # class BlogPost
170 # extend ActiveModel::Naming
171 # end
755af49 @fxn edit pass to apply API guideline wrt the use of "# =>" in example code
fxn authored
172 #
173 # BlogPost.model_name.human # => "Blog post"
174 #
e31077c @josevalim Small clean up in Naming and TTranslation tests.
josevalim authored
175 # Specify +options+ with additional translating options.
176 def human(options={})
177 return @human unless @klass.respond_to?(:lookup_ancestors) &&
178 @klass.respond_to?(:i18n_scope)
179
180 defaults = @klass.lookup_ancestors.map do |klass|
410a428 @josevalim Get rid of the alternate namespace lookup.
josevalim authored
181 klass.model_name.i18n_key
182 end
e31077c @josevalim Small clean up in Naming and TTranslation tests.
josevalim authored
183
75a960c Don't act destructively on ActiveModel::Name#human options hash. [#53…
John Firebaugh authored
184 defaults << options[:default] if options[:default]
e31077c @josevalim Small clean up in Naming and TTranslation tests.
josevalim authored
185 defaults << @human
186
f48d83b @carlosantoniodasilva Refactor human attribute name
carlosantoniodasilva authored
187 options = { :scope => [@klass.i18n_scope, :models], :count => 1, :default => defaults }.merge!(options.except(:default))
e31077c @josevalim Small clean up in Naming and TTranslation tests.
josevalim authored
188 I18n.translate(defaults.shift, options)
189 end
6e5aed0 @drogus Prepared ActiveModel::Naming to handle cases for namespaced isolated …
drogus authored
190
191 private
4f90b28 @spastorino Bring back AMo#i18n_key method
spastorino authored
192
193 def _singularize(string, replacement='_')
194 ActiveSupport::Inflector.underscore(string).tr('/', replacement)
195 end
566d717 @jeremy Move Class::ModelName to Active Support module core_ext
jeremy authored
196 end
2572af1 @rizwanreza Revised and added headings.
rizwanreza authored
197
c9a88a2 minor edits in AM documentation [ci skip]
Francesco Rodriguez authored
198 # == Active \Model \Naming
de12b5e @rizwanreza Revised naming.rb and lint.rb
rizwanreza authored
199 #
200 # Creates a +model_name+ method on your object.
b451de0 @spastorino Deletes trailing whitespaces (over text files only find * -type f -ex…
spastorino authored
201 #
fbc7c2b @mikel Adding ActiveModel::Naming documentation
mikel authored
202 # To implement, just extend ActiveModel::Naming in your object:
b451de0 @spastorino Deletes trailing whitespaces (over text files only find * -type f -ex…
spastorino authored
203 #
fbc7c2b @mikel Adding ActiveModel::Naming documentation
mikel authored
204 # class BookCover
9acd686 @snusnu Adds #key and #to_param to the AMo interface
snusnu authored
205 # extend ActiveModel::Naming
fbc7c2b @mikel Adding ActiveModel::Naming documentation
mikel authored
206 # end
b451de0 @spastorino Deletes trailing whitespaces (over text files only find * -type f -ex…
spastorino authored
207 #
755af49 @fxn edit pass to apply API guideline wrt the use of "# =>" in example code
fxn authored
208 # BookCover.model_name # => "BookCover"
209 # BookCover.model_name.human # => "Book cover"
b451de0 @spastorino Deletes trailing whitespaces (over text files only find * -type f -ex…
spastorino authored
210 #
d834755 @marcandre ActiveModel::Name#i18n_key: Fix doc and add tests
marcandre authored
211 # BookCover.model_name.i18n_key # => :book_cover
212 # BookModule::BookCover.model_name.i18n_key # => :"book_module/book_cover"
4f90b28 @spastorino Bring back AMo#i18n_key method
spastorino authored
213 #
fbc7c2b @mikel Adding ActiveModel::Naming documentation
mikel authored
214 # Providing the functionality that ActiveModel::Naming provides in your object
87615f2 update ActiveModel::Naming documentation
Francesco Rodriguez authored
215 # is required to pass the Active Model Lint test. So either extending the
216 # provided method below, or rolling your own is required.
1c4d28b @josh Move model naming into ActiveModel
josh authored
217 module Naming
218 # Returns an ActiveModel::Name object for module. It can be
87615f2 update ActiveModel::Naming documentation
Francesco Rodriguez authored
219 # used to retrieve all kinds of naming-related information
220 # (See ActiveModel::Name for more information).
b8e4f71 add example to ActiveModel::Naming#model_name [ci skip]
Francesco Rodriguez authored
221 #
222 # class Person < ActiveModel::Model
223 # end
224 #
225 # Person.model_name # => Person
226 # Person.model_name.class # => ActiveModel::Name
227 # Person.model_name.singular # => "person"
228 # Person.model_name.plural # => "people"
1c4d28b @josh Move model naming into ActiveModel
josh authored
229 def model_name
9c57bd8 @thedarkone Fix Namind#model_name.
thedarkone authored
230 @_model_name ||= begin
fd86a1b @josevalim Rely on a public contract between railties instead of accessing railt…
josevalim authored
231 namespace = self.parents.detect do |n|
232 n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
233 end
9c57bd8 @thedarkone Fix Namind#model_name.
thedarkone authored
234 ActiveModel::Name.new(self, namespace)
235 end
1c4d28b @josh Move model naming into ActiveModel
josh authored
236 end
6807b08 @drogus Moved a few methods from RecordIdentifier to ActiveModel::Naming
drogus authored
237
87615f2 update ActiveModel::Naming documentation
Francesco Rodriguez authored
238 # Returns the plural class name of a record or class.
6807b08 @drogus Moved a few methods from RecordIdentifier to ActiveModel::Naming
drogus authored
239 #
240 # ActiveModel::Naming.plural(post) # => "posts"
241 # ActiveModel::Naming.plural(Highrise::Person) # => "highrise_people"
242 def self.plural(record_or_class)
243 model_name_from_record_or_class(record_or_class).plural
244 end
245
87615f2 update ActiveModel::Naming documentation
Francesco Rodriguez authored
246 # Returns the singular class name of a record or class.
6807b08 @drogus Moved a few methods from RecordIdentifier to ActiveModel::Naming
drogus authored
247 #
248 # ActiveModel::Naming.singular(post) # => "post"
249 # ActiveModel::Naming.singular(Highrise::Person) # => "highrise_person"
250 def self.singular(record_or_class)
251 model_name_from_record_or_class(record_or_class).singular
252 end
253
87615f2 update ActiveModel::Naming documentation
Francesco Rodriguez authored
254 # Identifies whether the class name of a record or class is uncountable.
6807b08 @drogus Moved a few methods from RecordIdentifier to ActiveModel::Naming
drogus authored
255 #
256 # ActiveModel::Naming.uncountable?(Sheep) # => true
87615f2 update ActiveModel::Naming documentation
Francesco Rodriguez authored
257 # ActiveModel::Naming.uncountable?(Post) # => false
6807b08 @drogus Moved a few methods from RecordIdentifier to ActiveModel::Naming
drogus authored
258 def self.uncountable?(record_or_class)
259 plural(record_or_class) == singular(record_or_class)
260 end
261
bf1ac82 @drogus Add some documantation on new route_key and param_key in ActiveModel:…
drogus authored
262 # Returns string to use while generating route names. It differs for
263 # namespaced models regarding whether it's inside isolated engine.
264 #
36ebafd fix AM::Naming examples [ci skip]
Francesco Rodriguez authored
265 # # For isolated engine:
ba291a6 Trivial documentation fix for ActiveModel::Naming comment.
Dennis Taylor authored
266 # ActiveModel::Naming.singular_route_key(Blog::Post) #=> post
7280787 @josevalim Improve cache on route_key lookup.
josevalim authored
267 #
36ebafd fix AM::Naming examples [ci skip]
Francesco Rodriguez authored
268 # # For shared engine:
ba291a6 Trivial documentation fix for ActiveModel::Naming comment.
Dennis Taylor authored
269 # ActiveModel::Naming.singular_route_key(Blog::Post) #=> blog_post
7280787 @josevalim Improve cache on route_key lookup.
josevalim authored
270 def self.singular_route_key(record_or_class)
271 model_name_from_record_or_class(record_or_class).singular_route_key
272 end
273
274 # Returns string to use while generating route names. It differs for
275 # namespaced models regarding whether it's inside isolated engine.
276 #
36ebafd fix AM::Naming examples [ci skip]
Francesco Rodriguez authored
277 # # For isolated engine:
278 # ActiveModel::Naming.route_key(Blog::Post) #=> posts
bf1ac82 @drogus Add some documantation on new route_key and param_key in ActiveModel:…
drogus authored
279 #
36ebafd fix AM::Naming examples [ci skip]
Francesco Rodriguez authored
280 # # For shared engine:
281 # ActiveModel::Naming.route_key(Blog::Post) #=> blog_posts
7280787 @josevalim Improve cache on route_key lookup.
josevalim authored
282 #
283 # The route key also considers if the noun is uncountable and, in
284 # such cases, automatically appends _index.
6e5aed0 @drogus Prepared ActiveModel::Naming to handle cases for namespaced isolated …
drogus authored
285 def self.route_key(record_or_class)
286 model_name_from_record_or_class(record_or_class).route_key
287 end
288
bf1ac82 @drogus Add some documantation on new route_key and param_key in ActiveModel:…
drogus authored
289 # Returns string to use for params names. It differs for
290 # namespaced models regarding whether it's inside isolated engine.
291 #
36ebafd fix AM::Naming examples [ci skip]
Francesco Rodriguez authored
292 # # For isolated engine:
293 # ActiveModel::Naming.param_key(Blog::Post) #=> post
bf1ac82 @drogus Add some documantation on new route_key and param_key in ActiveModel:…
drogus authored
294 #
36ebafd fix AM::Naming examples [ci skip]
Francesco Rodriguez authored
295 # # For shared engine:
296 # ActiveModel::Naming.param_key(Blog::Post) #=> blog_post
6e5aed0 @drogus Prepared ActiveModel::Naming to handle cases for namespaced isolated …
drogus authored
297 def self.param_key(record_or_class)
298 model_name_from_record_or_class(record_or_class).param_key
299 end
300
ce06b8a @carlosantoniodasilva Refactor model name logic and make it a real private class method
carlosantoniodasilva authored
301 def self.model_name_from_record_or_class(record_or_class) #:nodoc:
302 if record_or_class.respond_to?(:model_name)
303 record_or_class.model_name
304 elsif record_or_class.respond_to?(:to_model)
305 record_or_class.to_model.class.model_name
306 else
920d9ee @Bertg Naming helpers should first check if passed object responds to model_…
Bertg authored
307 record_or_class.class.model_name
6807b08 @drogus Moved a few methods from RecordIdentifier to ActiveModel::Naming
drogus authored
308 end
ce06b8a @carlosantoniodasilva Refactor model name logic and make it a real private class method
carlosantoniodasilva authored
309 end
310 private_class_method :model_name_from_record_or_class
566d717 @jeremy Move Class::ModelName to Active Support module core_ext
jeremy authored
311 end
312 end
Something went wrong with that request. Please try again.