gorillib 0.1.11 → 0.4.0pre
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/.gitignore +1 -0
- data/.rspec +1 -2
- data/.yardopts +9 -0
- data/{CHANGELOG.textile → CHANGELOG.md} +35 -9
- data/Gemfile +21 -14
- data/Guardfile +19 -0
- data/{LICENSE.textile → LICENSE.md} +43 -29
- data/README.md +47 -52
- data/Rakefile +31 -30
- data/TODO.md +32 -0
- data/VERSION +1 -1
- data/examples/builder/ironfan.rb +133 -0
- data/examples/model/simple.rb +17 -0
- data/gorillib.gemspec +106 -86
- data/lib/alt/kernel/call_stack.rb +56 -0
- data/lib/gorillib/array/wrap.rb +53 -0
- data/lib/gorillib/base.rb +3 -3
- data/lib/gorillib/builder/field.rb +5 -0
- data/lib/gorillib/builder.rb +260 -0
- data/lib/gorillib/collection/has_collection.rb +31 -0
- data/lib/gorillib/collection.rb +129 -0
- data/lib/gorillib/configurable.rb +28 -0
- data/lib/gorillib/datetime/{flat.rb → to_flat.rb} +0 -0
- data/lib/gorillib/exception/confidence.rb +17 -0
- data/lib/gorillib/exception/raisers.rb +78 -0
- data/lib/gorillib/hash/mash.rb +202 -0
- data/lib/gorillib/hashlike/slice.rb +53 -19
- data/lib/gorillib/hashlike.rb +5 -3
- data/lib/gorillib/io/system_helpers.rb +30 -0
- data/lib/gorillib/logger/log.rb +18 -0
- data/lib/gorillib/metaprogramming/concern.rb +124 -0
- data/lib/gorillib/model/active_model_conversion.rb +68 -0
- data/lib/gorillib/model/active_model_naming.rb +87 -0
- data/lib/gorillib/model/active_model_shim.rb +33 -0
- data/lib/gorillib/model/base.rb +341 -0
- data/lib/gorillib/model/defaults.rb +71 -0
- data/lib/gorillib/model/errors.rb +14 -0
- data/lib/gorillib/model/factories.rb +372 -0
- data/lib/gorillib/model/field.rb +146 -0
- data/lib/gorillib/model/named_schema.rb +53 -0
- data/lib/gorillib/{struct/hashlike_iteration.rb → model/overlay.rb} +0 -0
- data/lib/gorillib/model/record_schema.rb +9 -0
- data/lib/gorillib/model/serialization.rb +23 -0
- data/lib/gorillib/model/validate.rb +22 -0
- data/lib/gorillib/model.rb +23 -0
- data/lib/gorillib/pathname.rb +78 -0
- data/lib/gorillib/{serialization.rb → serialization/to_wire.rb} +0 -0
- data/lib/gorillib/some.rb +11 -9
- data/lib/gorillib/string/constantize.rb +21 -14
- data/lib/gorillib/string/inflections.rb +6 -76
- data/lib/gorillib/string/inflector.rb +192 -0
- data/lib/gorillib/string/simple_inflector.rb +267 -0
- data/lib/gorillib/type/extended.rb +52 -0
- data/lib/gorillib/utils/capture_output.rb +28 -0
- data/lib/gorillib/utils/console.rb +131 -0
- data/lib/gorillib/utils/nuke_constants.rb +9 -0
- data/lib/gorillib/utils/stub_module.rb +33 -0
- data/spec/examples/builder/ironfan_spec.rb +37 -0
- data/spec/extlib/hash_spec.rb +64 -0
- data/spec/extlib/mash_spec.rb +312 -0
- data/spec/{array → gorillib/array}/compact_blank_spec.rb +2 -2
- data/spec/{array → gorillib/array}/extract_options_spec.rb +2 -2
- data/spec/gorillib/builder_spec.rb +187 -0
- data/spec/gorillib/collection_spec.rb +20 -0
- data/spec/gorillib/configurable_spec.rb +62 -0
- data/spec/{datetime → gorillib/datetime}/parse_spec.rb +3 -3
- data/spec/{datetime/flat_spec.rb → gorillib/datetime/to_flat_spec.rb} +4 -4
- data/spec/{enumerable → gorillib/enumerable}/sum_spec.rb +5 -5
- data/spec/gorillib/exception/raisers_spec.rb +60 -0
- data/spec/{hash → gorillib/hash}/compact_spec.rb +2 -2
- data/spec/{hash → gorillib/hash}/deep_compact_spec.rb +3 -3
- data/spec/{hash → gorillib/hash}/deep_merge_spec.rb +2 -2
- data/spec/{hash → gorillib/hash}/keys_spec.rb +2 -2
- data/spec/{hash → gorillib/hash}/reverse_merge_spec.rb +2 -2
- data/spec/{hash → gorillib/hash}/slice_spec.rb +2 -2
- data/spec/{hash → gorillib/hash}/zip_spec.rb +2 -2
- data/spec/{hashlike → gorillib/hashlike}/behave_same_as_hash_spec.rb +6 -3
- data/spec/{hashlike → gorillib/hashlike}/deep_hash_spec.rb +2 -2
- data/spec/{hashlike → gorillib/hashlike}/hashlike_behavior_spec.rb +32 -30
- data/spec/{hashlike → gorillib/hashlike}/hashlike_via_accessors_spec.rb +3 -3
- data/spec/{hashlike_spec.rb → gorillib/hashlike_spec.rb} +3 -3
- data/spec/{logger → gorillib/logger}/log_spec.rb +2 -2
- data/spec/{metaprogramming → gorillib/metaprogramming}/aliasing_spec.rb +3 -3
- data/spec/{metaprogramming → gorillib/metaprogramming}/class_attribute_spec.rb +3 -3
- data/spec/{metaprogramming → gorillib/metaprogramming}/delegation_spec.rb +3 -3
- data/spec/{metaprogramming → gorillib/metaprogramming}/singleton_class_spec.rb +3 -3
- data/spec/gorillib/model/record/defaults_spec.rb +108 -0
- data/spec/gorillib/model/record/factories_spec.rb +321 -0
- data/spec/gorillib/model/record/overlay_spec.rb +46 -0
- data/spec/gorillib/model/serialization_spec.rb +48 -0
- data/spec/gorillib/model_spec.rb +281 -0
- data/spec/{numeric → gorillib/numeric}/clamp_spec.rb +2 -2
- data/spec/{object → gorillib/object}/blank_spec.rb +2 -2
- data/spec/{object → gorillib/object}/try_dup_spec.rb +2 -2
- data/spec/{object → gorillib/object}/try_spec.rb +3 -2
- data/spec/gorillib/pathname_spec.rb +114 -0
- data/spec/{string → gorillib/string}/constantize_spec.rb +2 -2
- data/spec/{string → gorillib/string}/human_spec.rb +2 -2
- data/spec/{string → gorillib/string}/inflections_spec.rb +4 -3
- data/spec/{string → gorillib/string}/inflector_test_cases.rb +0 -0
- data/spec/{string → gorillib/string}/truncate_spec.rb +4 -10
- data/spec/gorillib/type/extended_spec.rb +120 -0
- data/spec/gorillib/utils/capture_output_spec.rb +71 -0
- data/spec/spec_helper.rb +8 -11
- data/spec/support/gorillib_test_helpers.rb +66 -0
- data/spec/support/hashlike_fuzzing_helper.rb +31 -33
- data/spec/support/hashlike_helper.rb +3 -3
- data/spec/support/model_test_helpers.rb +81 -0
- data/spec/support/shared_examples/included_module.rb +20 -0
- metadata +177 -158
- data/lib/gorillib/array/average.rb +0 -13
- data/lib/gorillib/array/sorted_median.rb +0 -11
- data/lib/gorillib/array/sorted_percentile.rb +0 -11
- data/lib/gorillib/array/sorted_sample.rb +0 -12
- data/lib/gorillib/dsl_object.rb +0 -64
- data/lib/gorillib/hash/indifferent_access.rb +0 -207
- data/lib/gorillib/hash/tree_merge.rb +0 -4
- data/lib/gorillib/hashlike/tree_merge.rb +0 -49
- data/lib/gorillib/metaprogramming/cattr_accessor.rb +0 -79
- data/lib/gorillib/metaprogramming/mattr_accessor.rb +0 -61
- data/lib/gorillib/receiver/active_model_shim.rb +0 -32
- data/lib/gorillib/receiver/acts_as_hash.rb +0 -195
- data/lib/gorillib/receiver/acts_as_loadable.rb +0 -42
- data/lib/gorillib/receiver/locale/en.yml +0 -27
- data/lib/gorillib/receiver/tree_diff.rb +0 -74
- data/lib/gorillib/receiver/validations.rb +0 -30
- data/lib/gorillib/receiver.rb +0 -402
- data/lib/gorillib/receiver_model.rb +0 -21
- data/lib/gorillib/struct/acts_as_hash.rb +0 -108
- data/notes/fancy_hashes_and_receivers.textile +0 -120
- data/notes/hash_rdocs.textile +0 -97
- data/spec/array/average_spec.rb +0 -24
- data/spec/array/sorted_median_spec.rb +0 -18
- data/spec/array/sorted_percentile_spec.rb +0 -24
- data/spec/array/sorted_sample_spec.rb +0 -28
- data/spec/dsl_object_spec.rb +0 -99
- data/spec/hash/indifferent_access_spec.rb +0 -391
- data/spec/metaprogramming/cattr_accessor_spec.rb +0 -43
- data/spec/metaprogramming/mattr_accessor_spec.rb +0 -45
- data/spec/receiver/acts_as_hash_spec.rb +0 -295
- data/spec/receiver_spec.rb +0 -551
- data/spec/struct/acts_as_hash_fuzz_spec.rb +0 -71
- data/spec/struct/acts_as_hash_spec.rb +0 -422
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
module Gorillib ; end
|
|
2
|
+
|
|
3
|
+
# String inflections define new methods on the String class to transform names for different purposes.
|
|
4
|
+
#
|
|
5
|
+
# "ScaleScore".underscore # => "scale_score"
|
|
6
|
+
#
|
|
7
|
+
# This doesn't define the full set of inflections -- only
|
|
8
|
+
#
|
|
9
|
+
# * camelize
|
|
10
|
+
# * snakeize
|
|
11
|
+
# * underscore
|
|
12
|
+
# * demodulize
|
|
13
|
+
#
|
|
14
|
+
module Gorillib::Inflector
|
|
15
|
+
extend self
|
|
16
|
+
|
|
17
|
+
def self.pluralizations
|
|
18
|
+
@pluralizations ||= {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def pluralize(str)
|
|
22
|
+
Gorillib::Inflector.pluralizations.fetch(str){ "#{str}s" }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# The reverse of +pluralize+, returns the singular form of a word in a string.
|
|
26
|
+
#
|
|
27
|
+
# Examples:
|
|
28
|
+
# "posts".singularize # => "post"
|
|
29
|
+
# # it's not very smart
|
|
30
|
+
# "octopi".singularize # => "octopi"
|
|
31
|
+
# "bonus".singularize # => "bonu"
|
|
32
|
+
# "boxes".singularize # => "boxe"
|
|
33
|
+
# "CamelOctopi".singularize # => "CamelOctopi"
|
|
34
|
+
def singularize(str)
|
|
35
|
+
Gorillib::Inflector.pluralizations.invert.fetch(str){ str.gsub(/s$/, '') }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Capitalizes the first word and turns underscores into spaces and strips a
|
|
39
|
+
# trailing "_id", if any. Like +titleize+, this is meant for creating pretty output.
|
|
40
|
+
#
|
|
41
|
+
# Examples:
|
|
42
|
+
# "employee_salary" # => "Employee salary"
|
|
43
|
+
# "author_id" # => "Author"
|
|
44
|
+
def humanize(lower_case_and_underscored_word)
|
|
45
|
+
result = lower_case_and_underscored_word.to_s.dup
|
|
46
|
+
result.gsub!(/_id$/, "")
|
|
47
|
+
result.gsub(/(_)?([a-z\d]*)/i){ "#{ $1 && ' ' }#{ $2.downcase}" }.gsub(/^\w/){ $&.upcase }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Capitalizes all the words and replaces some characters in the string to create
|
|
51
|
+
# a nicer looking title. +titleize+ is meant for creating pretty output. It is not
|
|
52
|
+
# used in the Rails internals.
|
|
53
|
+
#
|
|
54
|
+
# +titleize+ is also aliased as as +titlecase+.
|
|
55
|
+
#
|
|
56
|
+
# Examples:
|
|
57
|
+
# "man from the boondocks".titleize # => "Man From The Boondocks"
|
|
58
|
+
# "x-men: the last stand".titleize # => "X Men: The Last Stand"
|
|
59
|
+
# "TheManWithoutAPast".titleize # => "The Man Without A Past"
|
|
60
|
+
# "raiders_of_the_lost_ark".titleize # => "Raiders Of The Lost Ark"
|
|
61
|
+
def titleize(word)
|
|
62
|
+
humanize(underscore(word)).gsub(/\b('?[a-z])/){ $1.capitalize }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Create the name of a table like Rails does for models to table names. This method
|
|
66
|
+
# uses the +pluralize+ method on the last word in the string.
|
|
67
|
+
#
|
|
68
|
+
# Examples
|
|
69
|
+
# "RawScaledScorer".tableize # => "raw_scaled_scorers"
|
|
70
|
+
# "egg_and_ham".tableize # => "egg_and_hams"
|
|
71
|
+
# "fancyCategory".tableize # => "fancy_categories"
|
|
72
|
+
def tableize(class_name)
|
|
73
|
+
pluralize(underscore(class_name))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Create a class name from a plural table name like Rails does for table names to models.
|
|
77
|
+
# Note that this returns a string and not a Class. (To convert to an actual class
|
|
78
|
+
# follow +classify+ with +constantize+.)
|
|
79
|
+
#
|
|
80
|
+
# Examples:
|
|
81
|
+
# "egg_and_hams".classify # => "EggAndHam"
|
|
82
|
+
# "posts".classify # => "Post"
|
|
83
|
+
#
|
|
84
|
+
# Singular names are not handled correctly:
|
|
85
|
+
# "business".classify # => "Busines"
|
|
86
|
+
def classify(table_name)
|
|
87
|
+
# strip out any leading schema name
|
|
88
|
+
camelize(singularize(table_name.to_s.sub(/.*\./, '')))
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
# def uncountable_words #:doc
|
|
94
|
+
# %w( equipment information rice money species series fish )
|
|
95
|
+
# end
|
|
96
|
+
#
|
|
97
|
+
# def plural_rules #:doc:
|
|
98
|
+
# [
|
|
99
|
+
# [/(x|ch|ss|sh)$/i, '\1es'], # search, switch, fix, box, process, address
|
|
100
|
+
# [/([^aeiouy]|qu)y$/i, '\1ies'], # query, ability, agency
|
|
101
|
+
# [/(p)erson$/i, '\1eople'], # person, salesperson
|
|
102
|
+
# [/(m)an$/i, '\1en'], # man, woman, spokesman
|
|
103
|
+
# [/(c)hild$/i, '\1hildren'], # child
|
|
104
|
+
# [/s$/i, 's'], # no change (compatibility)
|
|
105
|
+
# [/$/, 's']
|
|
106
|
+
# ]
|
|
107
|
+
# end
|
|
108
|
+
#
|
|
109
|
+
# def singular_rules
|
|
110
|
+
# [
|
|
111
|
+
# [/(x|ch|ss|sh)es$/i, '\1'],
|
|
112
|
+
# [/([^aeiouy]|qu)ies$/i, '\1y'],
|
|
113
|
+
# [/(p)eople$/i, '\1\2erson'],
|
|
114
|
+
# [/(m)en$/i, '\1an'],
|
|
115
|
+
# [/(c)hildren$/i, '\1\2hild'],
|
|
116
|
+
# [/s$/i, '']
|
|
117
|
+
# ]
|
|
118
|
+
# end
|
|
119
|
+
|
|
120
|
+
# %w[
|
|
121
|
+
# equipment equipment
|
|
122
|
+
# information information
|
|
123
|
+
# rice rice
|
|
124
|
+
# money money
|
|
125
|
+
# species species
|
|
126
|
+
# series series
|
|
127
|
+
# fish fish
|
|
128
|
+
# ]
|
|
129
|
+
|
|
130
|
+
# def uncountable_words #:doc
|
|
131
|
+
# %w( equipment information rice money species series fish )
|
|
132
|
+
# end
|
|
133
|
+
#
|
|
134
|
+
# def plural_rules #:doc:
|
|
135
|
+
# [
|
|
136
|
+
# [/^(ox)$/i, '\1\2en'], # ox
|
|
137
|
+
# [/([m|l])ouse$/i, '\1ice'], # mouse, louse
|
|
138
|
+
# [/(matr|vert|ind)ix|ex$/i, '\1ices'], # matrix, vertex, index
|
|
139
|
+
# [/(x|ch|ss|sh)$/i, '\1es'], # search, switch, fix, box, process, address
|
|
140
|
+
# [/([^aeiouy]|qu)ies$/i, '\1y'],
|
|
141
|
+
# [/([^aeiouy]|qu)y$/i, '\1ies'], # query, ability, agency
|
|
142
|
+
# [/(hive)$/i, '\1s'], # archive, hive
|
|
143
|
+
# [/(?:([^f])fe|([lr])f)$/i, '\1\2ves'], # half, safe, wife
|
|
144
|
+
# [/sis$/i, 'ses'], # basis, diagnosis
|
|
145
|
+
# [/([ti])um$/i, '\1a'], # datum, medium
|
|
146
|
+
# [/(p)erson$/i, '\1eople'], # person, salesperson
|
|
147
|
+
# [/(m)an$/i, '\1en'], # man, woman, spokesman
|
|
148
|
+
# [/(c)hild$/i, '\1hildren'], # child
|
|
149
|
+
# [/(buffal|tomat)o$/i, '\1\2oes'], # buffalo, tomato
|
|
150
|
+
# [/(bu)s$/i, '\1\2ses'], # bus
|
|
151
|
+
# [/(alias)/i, '\1es'], # alias
|
|
152
|
+
# [/(octop|vir)us$/i, '\1i'], # octopus, virus - virus has no defined plural (according to Latin/dictionary.com), but viri is better than viruses/viruss
|
|
153
|
+
# [/(ax|cri|test)is$/i, '\1es'], # axis, crisis
|
|
154
|
+
# [/s$/i, 's'], # no change (compatibility)
|
|
155
|
+
# [/$/, 's']
|
|
156
|
+
# ]
|
|
157
|
+
# end
|
|
158
|
+
#
|
|
159
|
+
# def singular_rules
|
|
160
|
+
# [
|
|
161
|
+
# [/(matr)ices$/i, '\1ix'],
|
|
162
|
+
# [/(vert|ind)ices$/i, '\1ex'],
|
|
163
|
+
# [/^(ox)en/i, '\1'],
|
|
164
|
+
# [/(alias)es$/i, '\1'],
|
|
165
|
+
# [/([octop|vir])i$/i, '\1us'],
|
|
166
|
+
# [/(cris|ax|test)es$/i, '\1is'],
|
|
167
|
+
# [/(shoe)s$/i, '\1'],
|
|
168
|
+
# [/(o)es$/i, '\1'],
|
|
169
|
+
# [/(bus)es$/i, '\1'],
|
|
170
|
+
# [/([m|l])ice$/i, '\1ouse'],
|
|
171
|
+
# [/(x|ch|ss|sh)es$/i, '\1'],
|
|
172
|
+
# [/(m)ovies$/i, '\1\2ovie'],
|
|
173
|
+
# [/(s)eries$/i, '\1\2eries'],
|
|
174
|
+
# [/([^aeiouy]|qu)ies$/i, '\1y'],
|
|
175
|
+
# [/([lr])ves$/i, '\1f'],
|
|
176
|
+
# [/(tive)s$/i, '\1'],
|
|
177
|
+
# [/(hive)s$/i, '\1'],
|
|
178
|
+
# [/([^f])ves$/i, '\1fe'],
|
|
179
|
+
# [/([ti])a$/i, '\1um'],
|
|
180
|
+
# [/(p)eople$/i, '\1\2erson'],
|
|
181
|
+
# [/(m)en$/i, '\1an'],
|
|
182
|
+
# [/(s)tatus$/i, '\1\2tatus'],
|
|
183
|
+
# [/(c)hildren$/i, '\1\2hild'],
|
|
184
|
+
# [/(n)ews$/i, '\1\2ews'],
|
|
185
|
+
# [/s$/i, '']
|
|
186
|
+
# ]
|
|
187
|
+
# end
|
|
188
|
+
|
|
189
|
+
# inflect.plural(/$/, 's')
|
|
190
|
+
# inflect.plural(/s$/i, 's')
|
|
191
|
+
# inflect.plural(/^(ax|test)is$/i, '\1es')
|
|
192
|
+
# inflect.plural(/(octop|vir)us$/i, '\1i')
|
|
193
|
+
# inflect.plural(/(octop|vir)i$/i, '\1i')
|
|
194
|
+
# inflect.plural(/(alias|status)$/i, '\1es')
|
|
195
|
+
# inflect.plural(/(bu)s$/i, '\1ses')
|
|
196
|
+
# inflect.plural(/(buffal|tomat)o$/i, '\1oes')
|
|
197
|
+
# inflect.plural(/([ti])um$/i, '\1a')
|
|
198
|
+
# inflect.plural(/([ti])a$/i, '\1a')
|
|
199
|
+
# inflect.plural(/sis$/i, 'ses')
|
|
200
|
+
# inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
|
|
201
|
+
# inflect.plural(/(hive)$/i, '\1s')
|
|
202
|
+
# inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
|
|
203
|
+
# inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
|
|
204
|
+
# inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
|
|
205
|
+
# inflect.plural(/(m|l)ouse$/i, '\1ice')
|
|
206
|
+
# inflect.plural(/(m|l)ice$/i, '\1ice')
|
|
207
|
+
# inflect.plural(/^(ox)$/i, '\1en')
|
|
208
|
+
# inflect.plural(/^(oxen)$/i, '\1')
|
|
209
|
+
# inflect.plural(/(quiz)$/i, '\1zes')
|
|
210
|
+
|
|
211
|
+
# inflect.singular(/s$/i, '')
|
|
212
|
+
# inflect.singular(/(ss)$/i, '\1')
|
|
213
|
+
# inflect.singular(/(n)ews$/i, '\1ews')
|
|
214
|
+
# inflect.singular(/([ti])a$/i, '\1um')
|
|
215
|
+
# inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1\2sis')
|
|
216
|
+
# inflect.singular(/(^analy)(sis|ses)$/i, '\1sis')
|
|
217
|
+
# inflect.singular(/([^f])ves$/i, '\1fe')
|
|
218
|
+
# inflect.singular(/(hive)s$/i, '\1')
|
|
219
|
+
# inflect.singular(/(tive)s$/i, '\1')
|
|
220
|
+
# inflect.singular(/([lr])ves$/i, '\1f')
|
|
221
|
+
# inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
|
|
222
|
+
# inflect.singular(/(s)eries$/i, '\1eries')
|
|
223
|
+
# inflect.singular(/(m)ovies$/i, '\1ovie')
|
|
224
|
+
# inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
|
|
225
|
+
# inflect.singular(/(m|l)ice$/i, '\1ouse')
|
|
226
|
+
# inflect.singular(/(bus)(es)?$/i, '\1')
|
|
227
|
+
# inflect.singular(/(o)es$/i, '\1')
|
|
228
|
+
# inflect.singular(/(shoe)s$/i, '\1')
|
|
229
|
+
# inflect.singular(/(cris|test)(is|es)$/i, '\1is')
|
|
230
|
+
# inflect.singular(/^(a)x[ie]s$/i, '\1xis')
|
|
231
|
+
# inflect.singular(/(octop|vir)(us|i)$/i, '\1us')
|
|
232
|
+
# inflect.singular(/(alias|status)(es)?$/i, '\1')
|
|
233
|
+
# inflect.singular(/^(ox)en/i, '\1')
|
|
234
|
+
# inflect.singular(/(vert|ind)ices$/i, '\1ex')
|
|
235
|
+
# inflect.singular(/(matr)ices$/i, '\1ix')
|
|
236
|
+
# inflect.singular(/(quiz)zes$/i, '\1')
|
|
237
|
+
# inflect.singular(/(database)s$/i, '\1')
|
|
238
|
+
#
|
|
239
|
+
# inflect.irregular('person', 'people')
|
|
240
|
+
# inflect.irregular('man', 'men')
|
|
241
|
+
# inflect.irregular('child', 'children')
|
|
242
|
+
# inflect.irregular('sex', 'sexes')
|
|
243
|
+
# inflect.irregular('move', 'moves')
|
|
244
|
+
# inflect.irregular('cow', 'kine')
|
|
245
|
+
# inflect.irregular('zombie', 'zombies')
|
|
246
|
+
#
|
|
247
|
+
# inflect.uncountable(%w(equipment information rice money species series fish sheep jeans))
|
|
248
|
+
|
|
249
|
+
public
|
|
250
|
+
|
|
251
|
+
# def pluralize(word)
|
|
252
|
+
# result = word.dup
|
|
253
|
+
# plural_rules.each do |(rule, replacement)|
|
|
254
|
+
# break if result.gsub!(rule, replacement)
|
|
255
|
+
# end
|
|
256
|
+
# return result
|
|
257
|
+
# end
|
|
258
|
+
#
|
|
259
|
+
# def singularize(word)
|
|
260
|
+
# result = word.dup
|
|
261
|
+
# singular_rules.each do |(rule, replacement)|
|
|
262
|
+
# break if result.gsub!(rule, replacement)
|
|
263
|
+
# end
|
|
264
|
+
# return result
|
|
265
|
+
# end
|
|
266
|
+
|
|
267
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
require 'time'
|
|
3
|
+
|
|
4
|
+
class ::Long < ::Integer ; end
|
|
5
|
+
class ::Double < ::Float ; end
|
|
6
|
+
class ::Binary < ::String ; end
|
|
7
|
+
|
|
8
|
+
class ::Guid < ::String ; end
|
|
9
|
+
class ::IpAddress < ::String ; end
|
|
10
|
+
class ::Hostname < ::String ; end
|
|
11
|
+
|
|
12
|
+
class ::Url < ::String ; end
|
|
13
|
+
|
|
14
|
+
# require 'gorillib/metaprogramming/delegation'
|
|
15
|
+
#
|
|
16
|
+
# class ::Boolean < ::Object
|
|
17
|
+
# attr_accessor :val
|
|
18
|
+
# def initialize(val=nil)
|
|
19
|
+
# self.val = val
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# delegate :!, :to_s, :blank?, :frozen?, :nil?, :present?, :to => :val
|
|
23
|
+
# delegate :!=, :&, :<=>, :=~, :^, :|, :to => :val
|
|
24
|
+
#
|
|
25
|
+
# def inspect()
|
|
26
|
+
# "<Boolean #{val.inspect}>"
|
|
27
|
+
# end
|
|
28
|
+
# def try_dup()
|
|
29
|
+
# ::Boolean.new(val)
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# def self.true ; self.new(true) ; end
|
|
33
|
+
# def self.false ; self.new(false) ; end
|
|
34
|
+
#
|
|
35
|
+
# def is_a?(klass) val.is_a?(klass) || super ; end
|
|
36
|
+
# def kind_of?(klass) val.kind_of?(klass) || super ; end
|
|
37
|
+
# def instance_of?(klass) val.instance_of?(klass) || super ; end
|
|
38
|
+
#
|
|
39
|
+
# def !=(other_val) other_val = other_val.val if other_val.is_a?(::Boolean) ; (val != other_val) ; end
|
|
40
|
+
# def ==(other_val) other_val = other_val.val if other_val.is_a?(::Boolean) ; (val == other_val) ; end
|
|
41
|
+
# def ===(other_val) other_val = other_val.val if other_val.is_a?(::Boolean) ; (val === other_val) ; end
|
|
42
|
+
# def <=>(other_val) other_val = other_val.val if other_val.is_a?(::Boolean) ; (val <=> other_val) ; end
|
|
43
|
+
# def eql?(other_val) other_val = other_val.val if other_val.is_a?(::Boolean) ; (val.eql? other_val) ; end
|
|
44
|
+
# def equal?(other_val) other_val = other_val.val if other_val.is_a?(::Boolean) ; (val.equal? other_val) ; end
|
|
45
|
+
#
|
|
46
|
+
# end
|
|
47
|
+
|
|
48
|
+
# Datamapper also defines:
|
|
49
|
+
#
|
|
50
|
+
# Apikey BCryptHash Decimal URI UUID Slug CommaSeparatedList Csv IpAddress Json Yaml Enum Flag Discriminator
|
|
51
|
+
#
|
|
52
|
+
# maybe someday we will too...
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Gorillib
|
|
2
|
+
module TestHelpers
|
|
3
|
+
module_function
|
|
4
|
+
|
|
5
|
+
def dummy_stdio(stdin_text=nil)
|
|
6
|
+
stdin = stdin_text.nil? ? $stdin : StringIO.new(stdin_text)
|
|
7
|
+
new_fhs = [stdin, StringIO.new('', 'w'), StringIO.new('', 'w')]
|
|
8
|
+
old_fhs = [$stdin, $stdout, $stderr]
|
|
9
|
+
begin
|
|
10
|
+
$stdin, $stdout, $stderr = new_fhs
|
|
11
|
+
yield
|
|
12
|
+
ensure
|
|
13
|
+
$stdin, $stdout, $stderr = old_fhs
|
|
14
|
+
end
|
|
15
|
+
new_fhs[1..2]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
#
|
|
19
|
+
# Temporarily sets the global variables $stderr and $stdout to a capturable StringIO;
|
|
20
|
+
# restores them at the end, even if there is an error
|
|
21
|
+
#
|
|
22
|
+
def capture_output
|
|
23
|
+
dummy_stdio{ yield }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
alias_method :quiet_output, :capture_output
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#
|
|
2
|
+
# An inspecting delegator.
|
|
3
|
+
#
|
|
4
|
+
# Create a trap passing in any object of your choice.
|
|
5
|
+
#
|
|
6
|
+
# Any time a method is called on the trap, it prints the method name, all its
|
|
7
|
+
# args, and the direct caller.
|
|
8
|
+
#
|
|
9
|
+
# @example Did you know how basic operators work? Now you do!
|
|
10
|
+
#
|
|
11
|
+
# trapped_int = ItsATrap.new(3)
|
|
12
|
+
#
|
|
13
|
+
# trapped_int - 55
|
|
14
|
+
# [:-, [55], nil, "..."]
|
|
15
|
+
# => -52
|
|
16
|
+
#
|
|
17
|
+
# 55 - trapped_int
|
|
18
|
+
# [:coerce, [55], nil, "..."]
|
|
19
|
+
# => 52
|
|
20
|
+
#
|
|
21
|
+
# - trapped_int
|
|
22
|
+
# [:-@, [], nil, "..."]
|
|
23
|
+
# => -3
|
|
24
|
+
#
|
|
25
|
+
class ItsATrap < BasicObject
|
|
26
|
+
def initialize(obj=::Object.new, show_ret=false)
|
|
27
|
+
@obj = obj
|
|
28
|
+
@call_count = 0
|
|
29
|
+
@show_ret = show_ret
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# We implement to_s and inspect, because otherwise it's annoyingly noisy. :pretty_inspect makes pry happy.
|
|
33
|
+
|
|
34
|
+
def inspect() "~#{@obj.inspect}~" ; end
|
|
35
|
+
def to_s() @obj.to_s ; end
|
|
36
|
+
alias_method :pretty_inspect, :inspect
|
|
37
|
+
def methods() @obj.methods ; end
|
|
38
|
+
|
|
39
|
+
# These are defined on BasicObject, delegate them along with the rest
|
|
40
|
+
# BasicObject.instance_methods
|
|
41
|
+
# => [:==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]
|
|
42
|
+
|
|
43
|
+
def ==( *args, &block) ; __describe_and_send__(:==, *args, &block) ; end
|
|
44
|
+
def equal?(*args, &block) ; __describe_and_send__(:equal?, *args, &block) ; end
|
|
45
|
+
def !@( *args, &block) ; __describe_and_send__(:!, *args, &block) ; end
|
|
46
|
+
def !=( *args, &block) ; __describe_and_send__(:!=, *args, &block) ; end
|
|
47
|
+
def instance_eval(*args, &block) ; __describe_and_send__(:instance_eval, *args, &block) ; end
|
|
48
|
+
def instance_exec(*args, &block) ; __describe_and_send__(:instance_exec, *args, &block) ; end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
# Any time a method is called on the trap, it prints the method name, all its
|
|
54
|
+
# args, and the direct caller.
|
|
55
|
+
#
|
|
56
|
+
def method_missing(meth, *args, &block)
|
|
57
|
+
__describe_and_send__(meth, *args, &block)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def __describe_and_send__(meth, *args, &block)
|
|
61
|
+
pref = "%-3d %-14s %-15s" % [@call_count, __id__, self.to_s[0..14]]
|
|
62
|
+
@call_count += 1
|
|
63
|
+
$stderr.puts "%s %-15s <- %-30s %s -- %s" % [pref, meth.to_s[0..14], args.map(&:inspect).join(','), block, ::Kernel.caller.first]
|
|
64
|
+
ret = @obj.__send__(meth, *args, &block)
|
|
65
|
+
$stderr.puts "%s %-15s -> %s" % [pref, meth.to_s[0..14], ret.inspect] if @show_ret
|
|
66
|
+
ret
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
module Test
|
|
71
|
+
module_function
|
|
72
|
+
|
|
73
|
+
def create_class(name, *args, &block)
|
|
74
|
+
Object.class_eval do
|
|
75
|
+
remove_const(name) if self.const_defined?(name)
|
|
76
|
+
const_set(name, Class.new(*args, &block))
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def example_singleton(name, *args)
|
|
81
|
+
require 'singleton'
|
|
82
|
+
create_class(name, *args){ include ::Singleton }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class Module
|
|
88
|
+
|
|
89
|
+
#
|
|
90
|
+
# Lists the differences in methods between two modules/classes
|
|
91
|
+
#
|
|
92
|
+
# Breaks them down by providing module, and shows class and instance methods.
|
|
93
|
+
# @param other [Module] other class or module to compare with
|
|
94
|
+
# @param show_common [true,false] true to show methods they have in common; false by default
|
|
95
|
+
#
|
|
96
|
+
# @example Range has several extra instance methods; the Foo class and its instances have methods via the Happy module
|
|
97
|
+
# module Happy ; def hello() 3 ; end ; end
|
|
98
|
+
# class Foo ; include Enumerable ; include Happy ; extend Happy ; end
|
|
99
|
+
# { "Foo#" => { Happy => [:hello] },
|
|
100
|
+
# "Foo." => { Happy => [:hello] },
|
|
101
|
+
# "Range#" => { Range => [:each, :step, :begin, :end, :last, :exclude_end?, :cover?]} }
|
|
102
|
+
#
|
|
103
|
+
def compare_methods(other=Object, show_common=false)
|
|
104
|
+
result = Hash.new{|h,k| h[k] = Hash.new{|hh,hk| hh[hk] = [] } }
|
|
105
|
+
|
|
106
|
+
inst_ancestors_both = ancestors & other.ancestors
|
|
107
|
+
klass_ancestors_both = singleton_class.ancestors & other.singleton_class.ancestors
|
|
108
|
+
|
|
109
|
+
inst_meths = (self.instance_methods | other.instance_methods)
|
|
110
|
+
klass_meths = (self.methods | other.methods)
|
|
111
|
+
|
|
112
|
+
[ [:both, inst_ancestors_both, klass_ancestors_both],
|
|
113
|
+
[self, (self.ancestors - inst_ancestors_both), (self.singleton_class.ancestors - klass_ancestors_both)],
|
|
114
|
+
[other, (other.ancestors - inst_ancestors_both), (other.singleton_class.ancestors - klass_ancestors_both)],
|
|
115
|
+
].each do |mod, inst_anc, klass_anc|
|
|
116
|
+
inst_anc.reverse.each do |ancestor|
|
|
117
|
+
result["#{mod}#"][ancestor] = inst_meths & ancestor.instance_methods
|
|
118
|
+
inst_meths -= ancestor.instance_methods
|
|
119
|
+
end
|
|
120
|
+
klass_anc.reverse.each do |ancestor|
|
|
121
|
+
result["#{mod}."][ancestor] = klass_meths & ancestor.instance_methods
|
|
122
|
+
klass_meths -= ancestor.instance_methods
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
unless show_common then result.delete("both#") ; result.delete("both.") ; end
|
|
126
|
+
result.each{|type,hsh| hsh.reject!{|k,v| v.empty? } }
|
|
127
|
+
result.reject!{|type,hsh| hsh.empty? }
|
|
128
|
+
result
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# spec/spec_helper_lite.rb
|
|
2
|
+
|
|
3
|
+
# Conditionally creates empty or "stub" modules only if
|
|
4
|
+
# a) they are not already defined; and
|
|
5
|
+
# b) they are not auto-loadable.
|
|
6
|
+
#
|
|
7
|
+
# From http://objectsonrails.com/#sec-7-1
|
|
8
|
+
#
|
|
9
|
+
# @example Faking out ActiveModel
|
|
10
|
+
# # ...
|
|
11
|
+
# require_relative '../spec_helper_lite'
|
|
12
|
+
# stub_module 'ActiveModel::Conversion'
|
|
13
|
+
# stub_module 'ActiveModel::Naming'
|
|
14
|
+
# require_relative '../../app/models/post'
|
|
15
|
+
# # ...
|
|
16
|
+
#
|
|
17
|
+
def stub_module(full_name)
|
|
18
|
+
# Uses #const_get to attempt to reference the given module. If the module is
|
|
19
|
+
# defined, or if calling #const_get causes it to be auto-loaded, the method
|
|
20
|
+
# does nothing more. But if #const_get fails to turn up the module, it defines
|
|
21
|
+
# an anonymous empty module to act as a placeholder.
|
|
22
|
+
full_name.to_s.split(/::/).inject(Object) do |context, name|
|
|
23
|
+
begin
|
|
24
|
+
context.const_get(name)
|
|
25
|
+
rescue NameError
|
|
26
|
+
context.const_set(name, Module.new)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# refute
|
|
33
|
+
# does_not_allow
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
# related libs
|
|
3
|
+
require 'gorillib/model'
|
|
4
|
+
require 'gorillib/model/field'
|
|
5
|
+
require 'gorillib/model/defaults'
|
|
6
|
+
# libs under test
|
|
7
|
+
require 'gorillib/builder'
|
|
8
|
+
require 'gorillib/builder/field'
|
|
9
|
+
require 'gorillib/string/simple_inflector'
|
|
10
|
+
# testing helpers
|
|
11
|
+
|
|
12
|
+
load GORILLIB_ROOT_DIR('examples/builder/ironfan.rb')
|
|
13
|
+
|
|
14
|
+
module Gorillib::Test ; end
|
|
15
|
+
module Meta::Gorillib::Test ; end
|
|
16
|
+
|
|
17
|
+
describe Gorillib::Builder, :model_spec => true do
|
|
18
|
+
after(:each){ Gorillib::Test.nuke_constants ; Meta::Gorillib::Test.nuke_constants }
|
|
19
|
+
def example_cluster
|
|
20
|
+
Gorillib::Test.cluster
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
let(:ec_webnode ){ fac = example_cluster.facet(:webnode); fac.cluster(example_cluster) ; fac }
|
|
24
|
+
let(:ec_webnode_a){ svr = ec_webnode.server(:a); svr.facet(ec_webnode) ; svr }
|
|
25
|
+
|
|
26
|
+
# it 'is awesome'
|
|
27
|
+
|
|
28
|
+
context "collections get a {foo}_name accessor:" do
|
|
29
|
+
it("facet.cluster_name"){ ec_webnode.cluster_name.should == :yellowhat }
|
|
30
|
+
it("server.facet_name" ){ ec_webnode_a.facet_name.should == :webnode }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context "collections get a `has_{foo}` tester:" do
|
|
34
|
+
it("server.facet?" ){ ec_webnode_a.facet?.should be_true }
|
|
35
|
+
it("facet.has_server?"){ ec_webnode.should have_server(:a) }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'gorillib/hash/slice'
|
|
3
|
+
|
|
4
|
+
describe Hash, "only" do
|
|
5
|
+
before do
|
|
6
|
+
@hash = { :one => 'ONE', 'two' => 'TWO', 3 => 'THREE', 4 => nil }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should return a hash with only the given key(s)" do
|
|
10
|
+
@hash.only(:not_in_there).should == {}
|
|
11
|
+
@hash.only(4).should == {4 => nil}
|
|
12
|
+
@hash.only(:one).should == { :one => 'ONE' }
|
|
13
|
+
@hash.only(:one, 3).should == { :one => 'ONE', 3 => 'THREE' }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
describe Hash, "except" do
|
|
19
|
+
before do
|
|
20
|
+
@hash = { :one => 'ONE', 'two' => 'TWO', 3 => 'THREE' }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should return a hash without only the given key(s)" do
|
|
24
|
+
@hash.except(:one).should == { 'two' => 'TWO', 3 => 'THREE' }
|
|
25
|
+
@hash.except(:one, 3).should == { 'two' => 'TWO' }
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# describe Hash, 'to_params' do
|
|
30
|
+
# {
|
|
31
|
+
# { "foo" => "bar", "baz" => "bat" } => "foo=bar&baz=bat",
|
|
32
|
+
# { "foo" => [ "bar", "baz" ] } => "foo%5B%5D=bar&foo%5B%5D=baz",
|
|
33
|
+
# { "foo" => [ {"bar" => "1"}, {"bar" => 2} ] } => "foo%5B%5D%5Bbar%5D=1&foo%5B%5D%5Bbar%5D=2",
|
|
34
|
+
# { "foo" => { "bar" => [ {"baz" => 1}, {"baz" => "2"} ] } } => "foo%5Bbar%5D%5B%5D%5Bbaz%5D=1&foo%5Bbar%5D%5B%5D%5Bbaz%5D=2",
|
|
35
|
+
# { "foo" => {"1" => "bar", "2" => "baz"} } => "foo%5B1%5D=bar&foo%5B2%5D=baz"
|
|
36
|
+
# }.each do |hash, params|
|
|
37
|
+
# it "should covert hash: #{hash.inspect} to params: #{params.inspect}" do
|
|
38
|
+
# hash.to_params.split('&').sort.should == params.split('&').sort
|
|
39
|
+
# end
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# it 'should not leave a trailing &' do
|
|
43
|
+
# { :name => 'Bob', :address => { :street => '111 Ruby Ave.', :city => 'Ruby Central', :phones => ['111-111-1111', '222-222-2222'] } }.to_params.should_not match(/&$/)
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# it 'should encode query keys' do
|
|
47
|
+
# { 'First & Last' => 'Alice Smith' }.to_params.should == "First%20%26%20Last=Alice%20Smith"
|
|
48
|
+
# end
|
|
49
|
+
#
|
|
50
|
+
# it 'should encode query values' do
|
|
51
|
+
# { :name => 'Alice & Bob' }.to_params.should == "name=Alice%20%26%20Bob"
|
|
52
|
+
# end
|
|
53
|
+
# end
|
|
54
|
+
#
|
|
55
|
+
# describe Hash, 'to_mash' do
|
|
56
|
+
# before :each do
|
|
57
|
+
# @hash = Hash.new(10)
|
|
58
|
+
# end
|
|
59
|
+
#
|
|
60
|
+
# it "copies default Hash value to Mash" do
|
|
61
|
+
# @mash = @hash.to_mash
|
|
62
|
+
# @mash[:merb].should == 10
|
|
63
|
+
# end
|
|
64
|
+
# end
|