arunthampi-supermodel 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ Inflector.inflections do |inflect|
2
+ inflect.plural(/$/, 's')
3
+ inflect.plural(/s$/i, 's')
4
+ inflect.plural(/(ax|test)is$/i, '\1es')
5
+ inflect.plural(/(octop|vir)us$/i, '\1i')
6
+ inflect.plural(/(alias|status)$/i, '\1es')
7
+ inflect.plural(/(bu)s$/i, '\1ses')
8
+ inflect.plural(/(buffal|tomat)o$/i, '\1oes')
9
+ inflect.plural(/([ti])um$/i, '\1a')
10
+ inflect.plural(/sis$/i, 'ses')
11
+ inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
12
+ inflect.plural(/(hive)$/i, '\1s')
13
+ inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
14
+ inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
15
+ inflect.plural(/(matr|vert|ind)ix|ex$/i, '\1ices')
16
+ inflect.plural(/([m|l])ouse$/i, '\1ice')
17
+ inflect.plural(/^(ox)$/i, '\1en')
18
+ inflect.plural(/(quiz)$/i, '\1zes')
19
+
20
+ inflect.singular(/s$/i, '')
21
+ inflect.singular(/(n)ews$/i, '\1ews')
22
+ inflect.singular(/([ti])a$/i, '\1um')
23
+ inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1\2sis')
24
+ inflect.singular(/(^analy)ses$/i, '\1sis')
25
+ inflect.singular(/([^f])ves$/i, '\1fe')
26
+ inflect.singular(/(hive)s$/i, '\1')
27
+ inflect.singular(/(tive)s$/i, '\1')
28
+ inflect.singular(/([lr])ves$/i, '\1f')
29
+ inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
30
+ inflect.singular(/(s)eries$/i, '\1eries')
31
+ inflect.singular(/(m)ovies$/i, '\1ovie')
32
+ inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
33
+ inflect.singular(/([m|l])ice$/i, '\1ouse')
34
+ inflect.singular(/(bus)es$/i, '\1')
35
+ inflect.singular(/(o)es$/i, '\1')
36
+ inflect.singular(/(shoe)s$/i, '\1')
37
+ inflect.singular(/(cris|ax|test)es$/i, '\1is')
38
+ inflect.singular(/(octop|vir)i$/i, '\1us')
39
+ inflect.singular(/(alias|status)es$/i, '\1')
40
+ inflect.singular(/^(ox)en/i, '\1')
41
+ inflect.singular(/(vert|ind)ices$/i, '\1ex')
42
+ inflect.singular(/(matr)ices$/i, '\1ix')
43
+ inflect.singular(/(quiz)zes$/i, '\1')
44
+
45
+ inflect.irregular('person', 'people')
46
+ inflect.irregular('man', 'men')
47
+ inflect.irregular('child', 'children')
48
+ inflect.irregular('sex', 'sexes')
49
+ inflect.irregular('move', 'moves')
50
+
51
+ inflect.uncountable(%w(equipment information rice money species series fish sheep))
52
+ end
@@ -0,0 +1,277 @@
1
+ # This file is copied from the ActiveSupport project, which
2
+ # is a part of the Ruby On Rails web-framework (http://rubyonrails.org).
3
+ require 'singleton'
4
+
5
+ # The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,
6
+ # and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept
7
+ # in inflections.rb.
8
+ module Inflector
9
+ # A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
10
+ # inflection rules. Examples:
11
+ #
12
+ # Inflector.inflections do |inflect|
13
+ # inflect.plural /^(ox)$/i, '\1\2en'
14
+ # inflect.singular /^(ox)en/i, '\1'
15
+ #
16
+ # inflect.irregular 'octopus', 'octopi'
17
+ #
18
+ # inflect.uncountable "equipment"
19
+ # end
20
+ #
21
+ # New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
22
+ # pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
23
+ # already have been loaded.
24
+ class Inflections
25
+ include Singleton
26
+
27
+ attr_reader :plurals, :singulars, :uncountables
28
+
29
+ def initialize
30
+ @plurals, @singulars, @uncountables = [], [], []
31
+ end
32
+
33
+ # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
34
+ # The replacement should always be a string that may include references to the matched data from the rule.
35
+ def plural(rule, replacement)
36
+ @plurals.insert(0, [rule, replacement])
37
+ end
38
+
39
+ # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
40
+ # The replacement should always be a string that may include references to the matched data from the rule.
41
+ def singular(rule, replacement)
42
+ @singulars.insert(0, [rule, replacement])
43
+ end
44
+
45
+ # Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
46
+ # for strings, not regular expressions. You simply pass the irregular in singular and plural form.
47
+ #
48
+ # Examples:
49
+ # irregular 'octopus', 'octopi'
50
+ # irregular 'person', 'people'
51
+ def irregular(singular, plural)
52
+ plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
53
+ singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
54
+ end
55
+
56
+ # Add uncountable words that shouldn't be attempted inflected.
57
+ #
58
+ # Examples:
59
+ # uncountable "money"
60
+ # uncountable "money", "information"
61
+ # uncountable %w( money information rice )
62
+ def uncountable(*words)
63
+ (@uncountables << words).flatten!
64
+ end
65
+
66
+ # Clears the loaded inflections within a given scope (default is :all). Give the scope as a symbol of the inflection type,
67
+ # the options are: :plurals, :singulars, :uncountables
68
+ #
69
+ # Examples:
70
+ # clear :all
71
+ # clear :plurals
72
+ def clear(scope = :all)
73
+ case scope
74
+ when :all
75
+ @plurals, @singulars, @uncountables = [], [], []
76
+ else
77
+ instance_variable_set "@#{scope}", []
78
+ end
79
+ end
80
+ end
81
+
82
+ extend self
83
+
84
+ def inflections
85
+ if block_given?
86
+ yield Inflections.instance
87
+ else
88
+ Inflections.instance
89
+ end
90
+ end
91
+
92
+ # Returns the plural form of the word in the string.
93
+ #
94
+ # Examples
95
+ # "post".pluralize #=> "posts"
96
+ # "octopus".pluralize #=> "octopi"
97
+ # "sheep".pluralize #=> "sheep"
98
+ # "words".pluralize #=> "words"
99
+ # "the blue mailman".pluralize #=> "the blue mailmen"
100
+ # "CamelOctopus".pluralize #=> "CamelOctopi"
101
+ def pluralize(word)
102
+ result = word.to_s.dup
103
+
104
+ if inflections.uncountables.include?(result.downcase)
105
+ result
106
+ else
107
+ inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
108
+ result
109
+ end
110
+ end
111
+
112
+ # The reverse of pluralize, returns the singular form of a word in a string.
113
+ #
114
+ # Examples
115
+ # "posts".singularize #=> "post"
116
+ # "octopi".singularize #=> "octopus"
117
+ # "sheep".singluarize #=> "sheep"
118
+ # "word".singluarize #=> "word"
119
+ # "the blue mailmen".singularize #=> "the blue mailman"
120
+ # "CamelOctopi".singularize #=> "CamelOctopus"
121
+ def singularize(word)
122
+ result = word.to_s.dup
123
+
124
+ if inflections.uncountables.include?(result.downcase)
125
+ result
126
+ else
127
+ inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
128
+ result
129
+ end
130
+ end
131
+
132
+ # By default, camelize converts strings to UpperCamelCase. If the argument to camelize
133
+ # is set to ":lower" then camelize produces lowerCamelCase.
134
+ #
135
+ # camelize will also convert '/' to '::' which is useful for converting paths to namespaces
136
+ #
137
+ # Examples
138
+ # "active_record".camelize #=> "ActiveRecord"
139
+ # "active_record".camelize(:lower) #=> "activeRecord"
140
+ # "active_record/errors".camelize #=> "ActiveRecord::Errors"
141
+ # "active_record/errors".camelize(:lower) #=> "activeRecord::Errors"
142
+ def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
143
+ if first_letter_in_uppercase
144
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
145
+ else
146
+ lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
147
+ end
148
+ end
149
+
150
+ # Capitalizes all the words and replaces some characters in the string to create
151
+ # a nicer looking title. Titleize is meant for creating pretty output. It is not
152
+ # used in the Rails internals.
153
+ #
154
+ # titleize is also aliased as as titlecase
155
+ #
156
+ # Examples
157
+ # "man from the boondocks".titleize #=> "Man From The Boondocks"
158
+ # "x-men: the last stand".titleize #=> "X Men: The Last Stand"
159
+ def titleize(word)
160
+ humanize(underscore(word)).gsub(/\b([a-z])/) { $1.capitalize }
161
+ end
162
+
163
+ # The reverse of +camelize+. Makes an underscored form from the expression in the string.
164
+ #
165
+ # Changes '::' to '/' to convert namespaces to paths.
166
+ #
167
+ # Examples
168
+ # "ActiveRecord".underscore #=> "active_record"
169
+ # "ActiveRecord::Errors".underscore #=> active_record/errors
170
+ def underscore(camel_cased_word)
171
+ camel_cased_word.to_s.gsub(/::/, '/').
172
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
173
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
174
+ tr("-", "_").
175
+ downcase
176
+ end
177
+
178
+ # Replaces underscores with dashes in the string.
179
+ #
180
+ # Example
181
+ # "puni_puni" #=> "puni-puni"
182
+ def dasherize(underscored_word)
183
+ underscored_word.gsub(/_/, '-')
184
+ end
185
+
186
+ # Capitalizes the first word and turns underscores into spaces and strips _id.
187
+ # Like titleize, this is meant for creating pretty output.
188
+ #
189
+ # Examples
190
+ # "employee_salary" #=> "Employee salary"
191
+ # "author_id" #=> "Author"
192
+ def humanize(lower_case_and_underscored_word)
193
+ lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
194
+ end
195
+
196
+ # Removes the module part from the expression in the string
197
+ #
198
+ # Examples
199
+ # "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections"
200
+ # "Inflections".demodulize #=> "Inflections"
201
+ def demodulize(class_name_in_module)
202
+ class_name_in_module.to_s.gsub(/^.*::/, '')
203
+ end
204
+
205
+ # Create the name of a table like Rails does for models to table names. This method
206
+ # uses the pluralize method on the last word in the string.
207
+ #
208
+ # Examples
209
+ # "RawScaledScorer".tableize #=> "raw_scaled_scorers"
210
+ # "egg_and_ham".tableize #=> "egg_and_hams"
211
+ # "fancyCategory".tableize #=> "fancy_categories"
212
+ def tableize(class_name)
213
+ pluralize(underscore(class_name))
214
+ end
215
+
216
+ # Create a class name from a table name like Rails does for table names to models.
217
+ # Note that this returns a string and not a Class. (To convert to an actual class
218
+ # follow classify with constantize.)
219
+ #
220
+ # Examples
221
+ # "egg_and_hams".classify #=> "EggAndHam"
222
+ # "post".classify #=> "Post"
223
+ def classify(table_name)
224
+ # strip out any leading schema name
225
+ camelize(singularize(table_name.to_s.sub(/.*\./, '')))
226
+ end
227
+
228
+ # Creates a foreign key name from a class name.
229
+ # +separate_class_name_and_id_with_underscore+ sets whether
230
+ # the method should put '_' between the name and 'id'.
231
+ #
232
+ # Examples
233
+ # "Message".foreign_key #=> "message_id"
234
+ # "Message".foreign_key(false) #=> "messageid"
235
+ # "Admin::Post".foreign_key #=> "post_id"
236
+ def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
237
+ underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
238
+ end
239
+
240
+ # Constantize tries to find a declared constant with the name specified
241
+ # in the string. It raises a NameError when the name is not in CamelCase
242
+ # or is not initialized.
243
+ #
244
+ # Examples
245
+ # "Module".constantize #=> Module
246
+ # "Class".constantize #=> Class
247
+ def constantize(camel_cased_word)
248
+ unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
249
+ raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
250
+ end
251
+
252
+ Object.module_eval("::#{$1}", __FILE__, __LINE__)
253
+ end
254
+
255
+ # Ordinalize turns a number into an ordinal string used to denote the
256
+ # position in an ordered sequence such as 1st, 2nd, 3rd, 4th.
257
+ #
258
+ # Examples
259
+ # ordinalize(1) # => "1st"
260
+ # ordinalize(2) # => "2nd"
261
+ # ordinalize(1002) # => "1002nd"
262
+ # ordinalize(1003) # => "1003rd"
263
+ def ordinalize(number)
264
+ if (11..13).include?(number.to_i % 100)
265
+ "#{number}th"
266
+ else
267
+ case number.to_i % 10
268
+ when 1: "#{number}st"
269
+ when 2: "#{number}nd"
270
+ when 3: "#{number}rd"
271
+ else "#{number}th"
272
+ end
273
+ end
274
+ end
275
+ end
276
+
277
+ require File.dirname(__FILE__) + '/inflections'
@@ -0,0 +1,70 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe "SuperModel::Base #from_json method, with many attributes" do
4
+ before(:all) do
5
+ class Hotel < SuperModel::Base
6
+ has :name, :which_is => :text, :with_default_value => "Swissotel The Stamford"
7
+ has :star_rating, :which_is => :decimal, :with_default_value => 5.0
8
+ has :rooms, :which_is => :number, :with_default_value => 100
9
+ end
10
+
11
+ class Hospital < SuperModel::Base
12
+ has :name
13
+ end
14
+
15
+ class CrazyPerson < SuperModel::Base
16
+ has :name, :which_is => :text, :with_default_value => "Crazed McLovin"
17
+ has_many :hospitals
18
+ end
19
+
20
+ class Town < SuperModel::Base
21
+ has :name
22
+
23
+ has_one :hospital
24
+ end
25
+ end
26
+
27
+ after(:all) do
28
+ Object.send(:remove_const, :Hotel)
29
+ Object.send(:remove_const, :Hospital)
30
+ Object.send(:remove_const, :CrazyPerson)
31
+ end
32
+
33
+ it "should have the from_json method" do
34
+ Hotel.should respond_to(:from_json)
35
+ Hospital.should respond_to(:from_json)
36
+ CrazyPerson.should respond_to(:from_json)
37
+ Hospital.should respond_to(:from_json)
38
+ end
39
+
40
+ it "should instantiate an object when sent the from_json method with valid json as a parameter" do
41
+ h = Hotel.from_json("{\"name\":\"Swissotel The Stamford\",\"rooms\":200,\"star_rating\":4.0}")
42
+ h.class.should == Hotel
43
+ # Check whether all attributes are set correctly
44
+ h.name.should == "Swissotel The Stamford"
45
+ h.rooms.should == 200
46
+ h.star_rating.should == 4.0
47
+ end
48
+
49
+ it "should instantiate an object when sent the from_json method with valid JSON (containing a has_many association) as a parameter" do
50
+ crazy = CrazyPerson.from_json('{"name":"Crazed McLovin","hospitals":[{"name":"Crazy Hospital 1"},{"name":"Crazy Hospital 2"}]}')
51
+
52
+ crazy.name == "Crazed McLovin"
53
+ crazy.hospitals.size.should == 2
54
+
55
+ hospitals = crazy.hospitals.collect{|h| h.name }
56
+ hospitals.sort!
57
+
58
+ hospitals.first.should == 'Crazy Hospital 1'
59
+ hospitals.last.should == 'Crazy Hospital 2'
60
+ end
61
+
62
+ it "should instantiate an object when sent the from_json method with valid JSON (containing a has_one association) as a parameter" do
63
+ town = Town.from_json('{"name":"Cochin","hospital":{"name":"Crazy Hospital 1"}}')
64
+
65
+ town.name == "Cochin"
66
+ town.hospital.should_not == nil
67
+
68
+ town.hospital.name.should == 'Crazy Hospital 1'
69
+ end
70
+ end
@@ -0,0 +1,89 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe "A class which is a subclass of SuperModel::Base with a has_many association" do
4
+ before(:each) do
5
+ class Person < SuperModel::Base
6
+ has :name, :which_is => :text
7
+ end
8
+
9
+ class AgedPerson < SuperModel::Base
10
+ has :name
11
+ has :age, :which_is => :number, :with_default_value => 10
12
+ end
13
+
14
+ class Contact < SuperModel::Base
15
+ has_many :people
16
+ end
17
+
18
+ @c = Contact.new
19
+ @p1 = Person.new
20
+ @a1 = AgedPerson.new
21
+ end
22
+
23
+ after(:each) do
24
+ Object.send(:remove_const, :Person)
25
+ Object.send(:remove_const, :AgedPerson)
26
+ Object.send(:remove_const, :Contact)
27
+ end
28
+
29
+ it "should have an instance variable called has_many_associations which is a Hash with the key being :people" do
30
+ Contact.has_many_associations.class.should == Hash
31
+ Contact.has_many_associations.keys.should == [:people]
32
+ end
33
+
34
+ it "should have methods called people and add_person" do
35
+ @c.should respond_to(:people)
36
+ @c.should respond_to(:add_person)
37
+ end
38
+
39
+ it "should have a method called people which returns an empty array" do
40
+ @c.people.should == []
41
+ end
42
+
43
+ it "should be able to add a Person object to the association" do
44
+ @c.add_person(@p1)
45
+ @c.people.should == [@p1]
46
+ end
47
+
48
+ end
49
+
50
+ describe "An object instantiated from class which is a subclass of SuperModel::Base" do
51
+ before(:each) do
52
+ class Comment < SuperModel::Base
53
+ has :body
54
+ end
55
+
56
+ class Blog < SuperModel::Base
57
+ has :title
58
+ has_many :comments
59
+ end
60
+
61
+ @comment1 = Comment.new(:body => "I can haz redbull?")
62
+ @comment2 = Comment.new(:body => 'k thx bai')
63
+ @blog = Blog.new(:title => 'Lolcats Primer', :comments => [@comment1, @comment2])
64
+ @blog1 = Blog.new(:title => 'Lolcats Primer The Sequel', :comments => [{:body => 'can'}, {:body => 'haz'}])
65
+ end
66
+
67
+ after(:each) do
68
+ Object.send(:remove_const, :Comment)
69
+ Object.send(:remove_const, :Blog)
70
+ end
71
+
72
+ it "should be able to initialize with a hash which contains descendents of SuperModel::Base" do
73
+ @comment1.body.should == "I can haz redbull?"
74
+ @comment2.body.should == "k thx bai"
75
+
76
+ @blog.title.should == 'Lolcats Primer'
77
+ @blog.comments.should == [@comment1, @comment2]
78
+ end
79
+
80
+ it "should be able to initialize from a hash which contains only Strings" do
81
+ @blog1.title.should == 'Lolcats Primer The Sequel'
82
+
83
+ comment_bodies = @blog1.comments.collect{|c| c.body }
84
+ comment_bodies.sort!
85
+
86
+ comment_bodies.first.should == 'can'
87
+ comment_bodies.last.should == 'haz'
88
+ end
89
+ end