Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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