motion-support 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile +1 -1
- data/README.md +231 -2
- data/Rakefile +3 -3
- data/app/app_delegate.rb +0 -2
- data/examples/Inflector/.gitignore +16 -0
- data/examples/Inflector/Gemfile +5 -0
- data/examples/Inflector/Rakefile +13 -0
- data/examples/Inflector/app/app_delegate.rb +8 -0
- data/examples/Inflector/app/inflections.rb +5 -0
- data/examples/Inflector/app/inflector_view_controller.rb +120 -0
- data/examples/Inflector/app/words_view_controller.rb +101 -0
- data/examples/Inflector/resources/Default-568h@2x.png +0 -0
- data/examples/Inflector/spec/main_spec.rb +9 -0
- data/lib/motion-support/core_ext/array.rb +13 -0
- data/lib/motion-support/core_ext/class.rb +8 -0
- data/lib/motion-support/core_ext/hash.rb +16 -0
- data/lib/motion-support/core_ext/integer.rb +9 -0
- data/lib/motion-support/core_ext/module.rb +14 -0
- data/lib/motion-support/core_ext/numeric.rb +8 -0
- data/lib/motion-support/core_ext/object.rb +14 -0
- data/lib/motion-support/core_ext/range.rb +8 -0
- data/lib/motion-support/core_ext/string.rb +14 -0
- data/lib/motion-support/core_ext/time.rb +19 -0
- data/lib/motion-support/core_ext.rb +3 -0
- data/lib/motion-support/inflector.rb +12 -156
- data/lib/motion-support.rb +5 -5
- data/motion/_stdlib/cgi.rb +22 -0
- data/motion/_stdlib/date.rb +77 -0
- data/motion/_stdlib/time.rb +19 -0
- data/motion/core_ext/array/access.rb +28 -0
- data/motion/core_ext/array/conversions.rb +86 -0
- data/motion/core_ext/array/extract_options.rb +11 -0
- data/motion/core_ext/array/grouping.rb +99 -0
- data/motion/core_ext/array/prepend_and_append.rb +7 -0
- data/motion/core_ext/array/wrap.rb +45 -0
- data/{lib/motion-support → motion/core_ext}/array.rb +0 -4
- data/motion/core_ext/class/attribute.rb +119 -0
- data/motion/core_ext/class/attribute_accessors.rb +168 -0
- data/motion/core_ext/date/acts_like.rb +8 -0
- data/motion/core_ext/date/calculations.rb +117 -0
- data/motion/core_ext/date/conversions.rb +56 -0
- data/motion/core_ext/date_and_time/calculations.rb +232 -0
- data/motion/core_ext/enumerable.rb +90 -0
- data/motion/core_ext/hash/deep_merge.rb +27 -0
- data/motion/core_ext/hash/except.rb +15 -0
- data/motion/core_ext/hash/indifferent_access.rb +19 -0
- data/motion/core_ext/hash/keys.rb +138 -0
- data/motion/core_ext/hash/reverse_merge.rb +22 -0
- data/motion/core_ext/hash/slice.rb +40 -0
- data/motion/core_ext/integer/inflections.rb +27 -0
- data/motion/core_ext/integer/multiple.rb +10 -0
- data/motion/core_ext/integer/time.rb +41 -0
- data/{lib/motion-support → motion/core_ext}/metaclass.rb +0 -0
- data/motion/core_ext/module/aliasing.rb +69 -0
- data/motion/core_ext/module/anonymous.rb +19 -0
- data/motion/core_ext/module/attr_internal.rb +38 -0
- data/motion/core_ext/module/attribute_accessors.rb +64 -0
- data/motion/core_ext/module/delegation.rb +175 -0
- data/motion/core_ext/module/introspection.rb +60 -0
- data/motion/core_ext/module/reachable.rb +5 -0
- data/motion/core_ext/module/remove_method.rb +12 -0
- data/motion/core_ext/ns_dictionary.rb +11 -0
- data/motion/core_ext/numeric/bytes.rb +44 -0
- data/motion/core_ext/numeric/conversions.rb +7 -0
- data/motion/core_ext/numeric/time.rb +75 -0
- data/motion/core_ext/object/acts_like.rb +10 -0
- data/motion/core_ext/object/blank.rb +105 -0
- data/motion/core_ext/object/deep_dup.rb +44 -0
- data/motion/core_ext/object/duplicable.rb +83 -0
- data/motion/core_ext/object/instance_variables.rb +28 -0
- data/motion/core_ext/object/to_param.rb +58 -0
- data/motion/core_ext/object/to_query.rb +26 -0
- data/motion/core_ext/object/try.rb +78 -0
- data/motion/core_ext/range/include_range.rb +23 -0
- data/motion/core_ext/range/overlaps.rb +8 -0
- data/motion/core_ext/regexp.rb +5 -0
- data/motion/core_ext/string/access.rb +104 -0
- data/motion/core_ext/string/behavior.rb +6 -0
- data/motion/core_ext/string/exclude.rb +11 -0
- data/motion/core_ext/string/filters.rb +55 -0
- data/motion/core_ext/string/indent.rb +43 -0
- data/motion/core_ext/string/inflections.rb +195 -0
- data/motion/core_ext/string/starts_ends_with.rb +4 -0
- data/motion/core_ext/string/strip.rb +24 -0
- data/motion/core_ext/time/acts_like.rb +8 -0
- data/motion/core_ext/time/calculations.rb +215 -0
- data/motion/core_ext/time/conversions.rb +52 -0
- data/motion/duration.rb +104 -0
- data/motion/hash_with_indifferent_access.rb +251 -0
- data/motion/inflections.rb +67 -0
- data/motion/inflector/inflections.rb +203 -0
- data/motion/inflector/methods.rb +321 -0
- data/{lib/motion-support → motion}/logger.rb +0 -0
- data/{lib/motion-support → motion}/version.rb +1 -1
- data/motion-support.gemspec +2 -2
- data/spec/motion-support/_helpers/constantize_test_cases.rb +75 -0
- data/spec/motion-support/_helpers/inflector_test_cases.rb +313 -0
- data/spec/motion-support/core_ext/array/access_spec.rb +29 -0
- data/spec/motion-support/core_ext/array/conversion_spec.rb +60 -0
- data/spec/motion-support/core_ext/array/extract_options_spec.rb +15 -0
- data/spec/motion-support/core_ext/array/grouping_spec.rb +85 -0
- data/spec/motion-support/core_ext/array/prepend_and_append_spec.rb +25 -0
- data/spec/motion-support/core_ext/array/wrap_spec.rb +19 -0
- data/spec/motion-support/{array_spec.rb → core_ext/array_spec.rb} +0 -5
- data/spec/motion-support/core_ext/class/attribute_accessor_spec.rb +127 -0
- data/spec/motion-support/core_ext/class/attribute_spec.rb +92 -0
- data/spec/motion-support/core_ext/date/acts_like_spec.rb +11 -0
- data/spec/motion-support/core_ext/date/calculation_spec.rb +186 -0
- data/spec/motion-support/core_ext/date/conversion_spec.rb +18 -0
- data/spec/motion-support/core_ext/date_and_time/calculation_spec.rb +336 -0
- data/spec/motion-support/core_ext/enumerable_spec.rb +130 -0
- data/spec/motion-support/core_ext/hash/deep_merge_spec.rb +32 -0
- data/spec/motion-support/core_ext/hash/except_spec.rb +43 -0
- data/spec/motion-support/core_ext/hash/key_spec.rb +230 -0
- data/spec/motion-support/core_ext/hash/reverse_merge_spec.rb +26 -0
- data/spec/motion-support/core_ext/hash/slice_spec.rb +61 -0
- data/spec/motion-support/core_ext/integer/inflection_spec.rb +23 -0
- data/spec/motion-support/core_ext/integer/multiple_spec.rb +19 -0
- data/spec/motion-support/{metaclass_spec.rb → core_ext/metaclass_spec.rb} +0 -0
- data/spec/motion-support/core_ext/module/aliasing_spec.rb +143 -0
- data/spec/motion-support/core_ext/module/anonymous_spec.rb +29 -0
- data/spec/motion-support/core_ext/module/attr_internal_spec.rb +104 -0
- data/spec/motion-support/core_ext/module/attribute_accessor_spec.rb +86 -0
- data/spec/motion-support/core_ext/module/delegation_spec.rb +136 -0
- data/spec/motion-support/core_ext/module/introspection_spec.rb +70 -0
- data/spec/motion-support/core_ext/module/reachable_spec.rb +61 -0
- data/spec/motion-support/core_ext/module/remove_method_spec.rb +25 -0
- data/spec/motion-support/core_ext/numeric/bytes_spec.rb +43 -0
- data/spec/motion-support/core_ext/object/acts_like_spec.rb +21 -0
- data/spec/motion-support/core_ext/object/blank_spec.rb +54 -0
- data/spec/motion-support/core_ext/object/deep_dup_spec.rb +54 -0
- data/spec/motion-support/core_ext/object/duplicable_spec.rb +31 -0
- data/spec/motion-support/core_ext/object/instance_variable_spec.rb +19 -0
- data/spec/motion-support/core_ext/object/to_param_spec.rb +75 -0
- data/spec/motion-support/core_ext/object/to_query_spec.rb +37 -0
- data/spec/motion-support/core_ext/object/try_spec.rb +92 -0
- data/spec/motion-support/core_ext/range/include_range_spec.rb +31 -0
- data/spec/motion-support/core_ext/range/overlap_spec.rb +43 -0
- data/spec/motion-support/core_ext/regexp_spec.rb +7 -0
- data/spec/motion-support/core_ext/string/access_spec.rb +53 -0
- data/spec/motion-support/core_ext/string/behavior_spec.rb +7 -0
- data/spec/motion-support/core_ext/string/exclude_spec.rb +8 -0
- data/spec/motion-support/core_ext/string/filter_spec.rb +48 -0
- data/spec/motion-support/core_ext/string/indent_spec.rb +56 -0
- data/spec/motion-support/core_ext/string/inflection_spec.rb +142 -0
- data/spec/motion-support/core_ext/string/starts_end_with_spec.rb +14 -0
- data/spec/motion-support/core_ext/string/strip_spec.rb +34 -0
- data/spec/motion-support/core_ext/string_spec.rb +88 -0
- data/spec/motion-support/core_ext/time/acts_like_spec.rb +11 -0
- data/spec/motion-support/core_ext/time/calculation_spec.rb +201 -0
- data/spec/motion-support/core_ext/time/conversion_spec.rb +54 -0
- data/spec/motion-support/duration_spec.rb +107 -0
- data/spec/motion-support/hash_with_indifferent_access_spec.rb +605 -0
- data/spec/motion-support/inflector_spec.rb +474 -35
- data/spec/motion-support/ns_dictionary_spec.rb +29 -0
- metadata +212 -35
- data/lib/motion-support/cattr_accessor.rb +0 -19
- data/lib/motion-support/class_inheritable_accessor.rb +0 -23
- data/lib/motion-support/class_inheritable_array.rb +0 -29
- data/lib/motion-support/hash.rb +0 -31
- data/lib/motion-support/nilclass.rb +0 -5
- data/lib/motion-support/object.rb +0 -17
- data/lib/motion-support/string.rb +0 -71
- data/spec/motion-support/cattr_accessor_spec.rb +0 -49
- data/spec/motion-support/class_inheritable_accessor_spec.rb +0 -49
- data/spec/motion-support/class_inheritable_array_spec.rb +0 -61
- data/spec/motion-support/hash_spec.rb +0 -31
- data/spec/motion-support/nilclass_spec.rb +0 -5
- data/spec/motion-support/object_spec.rb +0 -43
- data/spec/motion-support/string_spec.rb +0 -145
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'motion-require'
|
2
|
+
|
3
|
+
files = [
|
4
|
+
'_stdlib/date',
|
5
|
+
'_stdlib/time',
|
6
|
+
'core_ext/time/acts_like',
|
7
|
+
'core_ext/time/calculations',
|
8
|
+
'core_ext/time/conversions',
|
9
|
+
'core_ext/date/acts_like',
|
10
|
+
'core_ext/date/calculations',
|
11
|
+
'core_ext/date/conversions',
|
12
|
+
'core_ext/date_and_time/calculations',
|
13
|
+
'core_ext/integer/time',
|
14
|
+
'core_ext/numeric/time',
|
15
|
+
'core_ext/object/acts_like',
|
16
|
+
'duration'
|
17
|
+
].map { |file| File.expand_path(File.join(File.dirname(__FILE__), "/../../../motion", "#{file}.rb")) }
|
18
|
+
|
19
|
+
Motion::Require.all(files)
|
@@ -1,156 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
def reset
|
15
|
-
# Put singular-form to plural form transformations here
|
16
|
-
@plurals = [
|
17
|
-
[/^person$/, 'people'],
|
18
|
-
[/^man$/, 'men'],
|
19
|
-
[/^child$/, 'children'],
|
20
|
-
[/^sex$/, 'sexes'],
|
21
|
-
[/^move$/, 'moves'],
|
22
|
-
[/^cow$/, 'kine'],
|
23
|
-
[/^zombie$/, 'zombies'],
|
24
|
-
[/(quiz)$/i, '\1zes'],
|
25
|
-
[/^(oxen)$/i, '\1'],
|
26
|
-
[/^(ox)$/i, '\1en'],
|
27
|
-
[/^(m|l)ice$/i, '\1ice'],
|
28
|
-
[/^(m|l)ouse$/i, '\1ice'],
|
29
|
-
[/(matr|vert|ind)(?:ix|ex)$/i, '\1ices'],
|
30
|
-
[/(x|ch|ss|sh)$/i, '\1es'],
|
31
|
-
[/([^aeiouy]|qu)y$/i, '\1ies'],
|
32
|
-
[/(hive)$/i, '\1s'],
|
33
|
-
[/(?:([^f])fe|([lr])f)$/i, '\1\2ves'],
|
34
|
-
[/sis$/i, 'ses'],
|
35
|
-
[/([ti])a$/i, '\1a'],
|
36
|
-
[/([ti])um$/i, '\1a'],
|
37
|
-
[/(buffal|tomat)o$/i, '\1oes'],
|
38
|
-
[/(bu)s$/i, '\1ses'],
|
39
|
-
[/(alias|status)$/i, '\1es'],
|
40
|
-
[/(octop|vir)i$/i, '\1i'],
|
41
|
-
[/(octop|vir|alumn)us$/i, '\1i'],
|
42
|
-
[/^(ax|test)is$/i, '\1es'],
|
43
|
-
[/s$/i, 's'],
|
44
|
-
[/$/, 's']
|
45
|
-
]
|
46
|
-
|
47
|
-
# Put plural-form to singular form transformations here
|
48
|
-
@singulars = [
|
49
|
-
[/^people$/, 'person'],
|
50
|
-
[/^men$/, 'man'],
|
51
|
-
[/^children$/, 'child'],
|
52
|
-
[/^sexes$/, 'sex'],
|
53
|
-
[/^moves$/, 'move'],
|
54
|
-
[/^kine$/, 'cow'],
|
55
|
-
[/^zombies$/, 'zombie'],
|
56
|
-
[/(database)s$/i, '\1'],
|
57
|
-
[/(quiz)zes$/i, '\1'],
|
58
|
-
[/(matr)ices$/i, '\1ix'],
|
59
|
-
[/(vert|ind)ices$/i, '\1ex'],
|
60
|
-
[/^(ox)en/i, '\1'],
|
61
|
-
[/(alias|status)(es)?$/i, '\1'],
|
62
|
-
[/(octop|vir|alumn)(us|i)$/i, '\1us'],
|
63
|
-
[/^(a)x[ie]s$/i, '\1xis'],
|
64
|
-
[/(cris|test)(is|es)$/i, '\1is'],
|
65
|
-
[/(shoe)s$/i, '\1'],
|
66
|
-
[/(o)es$/i, '\1'],
|
67
|
-
[/(bus)(es)?$/i, '\1'],
|
68
|
-
[/^(m|l)ice$/i, '\1ouse'],
|
69
|
-
[/(x|ch|ss|sh)es$/i, '\1'],
|
70
|
-
[/(m)ovies$/i, '\1ovie'],
|
71
|
-
[/(s)eries$/i, '\1eries'],
|
72
|
-
[/([^aeiouy]|qu)ies$/i, '\1y'],
|
73
|
-
[/([lr])ves$/i, '\1f'],
|
74
|
-
[/(tive)s$/i, '\1'],
|
75
|
-
[/(hive)s$/i, '\1'],
|
76
|
-
[/([^f])ves$/i, '\1fe'],
|
77
|
-
[/(^analy)(sis|ses)$/i, '\1sis'],
|
78
|
-
[/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis'],
|
79
|
-
[/([ti])a$/i, '\1um'],
|
80
|
-
[/(n)ews$/i, '\1ews'],
|
81
|
-
[/(ss)$/i, '\1'],
|
82
|
-
[/s$/i, '']
|
83
|
-
]
|
84
|
-
|
85
|
-
@irregulars = [
|
86
|
-
]
|
87
|
-
|
88
|
-
@uncountables = [
|
89
|
-
'equipment',
|
90
|
-
'information',
|
91
|
-
'rice',
|
92
|
-
'money',
|
93
|
-
'species',
|
94
|
-
'series',
|
95
|
-
'fish',
|
96
|
-
'sheep',
|
97
|
-
'jeans',
|
98
|
-
'police'
|
99
|
-
]
|
100
|
-
end
|
101
|
-
|
102
|
-
attr_reader :plurals, :singulars, :uncountables, :irregulars
|
103
|
-
|
104
|
-
def self.inflections
|
105
|
-
if block_given?
|
106
|
-
yield Inflector.instance
|
107
|
-
else
|
108
|
-
Inflector.instance
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def uncountable(word)
|
113
|
-
@uncountables << word
|
114
|
-
end
|
115
|
-
|
116
|
-
def singular(rule, replacement)
|
117
|
-
@singulars << [rule, replacement]
|
118
|
-
end
|
119
|
-
|
120
|
-
def plural(rule, replacement)
|
121
|
-
@plurals << [rule, replacement]
|
122
|
-
end
|
123
|
-
|
124
|
-
def irregular(rule, replacement)
|
125
|
-
@irregulars << [rule, replacement]
|
126
|
-
end
|
127
|
-
|
128
|
-
def uncountable?(word)
|
129
|
-
return word if @uncountables.include?(word.downcase)
|
130
|
-
false
|
131
|
-
end
|
132
|
-
|
133
|
-
def inflect(word, direction) #nodoc
|
134
|
-
return word if uncountable?(word)
|
135
|
-
|
136
|
-
subject = word.dup
|
137
|
-
|
138
|
-
@irregulars.each do |rule|
|
139
|
-
return subject if subject.gsub!(rule.first, rule.last)
|
140
|
-
end
|
141
|
-
|
142
|
-
sense_group = direction == :singularize ? @singulars : @plurals
|
143
|
-
sense_group.each do |rule|
|
144
|
-
return subject if subject.gsub!(rule.first, rule.last)
|
145
|
-
end
|
146
|
-
subject
|
147
|
-
end
|
148
|
-
|
149
|
-
def singularize(word)
|
150
|
-
inflect word, :singularize
|
151
|
-
end
|
152
|
-
|
153
|
-
def pluralize(word)
|
154
|
-
inflect word, :pluralize
|
155
|
-
end
|
156
|
-
end
|
1
|
+
require 'motion-require'
|
2
|
+
|
3
|
+
files = [
|
4
|
+
"inflector/inflections",
|
5
|
+
"inflector/methods",
|
6
|
+
"inflections",
|
7
|
+
"core_ext/string/inflections",
|
8
|
+
|
9
|
+
"core_ext/array/prepend_and_append"
|
10
|
+
].map { |file| File.expand_path(File.join(File.dirname(__FILE__), "/../../motion", "#{file}.rb")) }
|
11
|
+
|
12
|
+
Motion::Require.all(files)
|
data/lib/motion-support.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
|
3
|
-
Dir.glob(File.
|
4
|
-
|
5
|
-
|
1
|
+
require 'motion-require'
|
2
|
+
|
3
|
+
Motion::Require.all(Dir.glob(File.expand_path('../../motion/**/*.rb', __FILE__)))
|
4
|
+
|
5
|
+
at_exit { puts "\nWARNING: Automatic dependency detection does not work with motion-support. Turn it off in your Rakefile:\n\n app.detect_dependencies = false\n\n" if Motion::Project::App.config.detect_dependencies }
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# This is a very small part of the CGI class, borrowed from the Rubinius sources
|
2
|
+
class CGI
|
3
|
+
@@accept_charset="UTF-8" unless defined?(@@accept_charset)
|
4
|
+
# URL-encode a string.
|
5
|
+
# url_encoded_string = CGI::escape("'Stop!' said Fred")
|
6
|
+
# # => "%27Stop%21%27+said+Fred"
|
7
|
+
def CGI::escape(string)
|
8
|
+
string.gsub(/([^ a-zA-Z0-9_.-]+)/) do
|
9
|
+
'%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
|
10
|
+
end.tr(' ', '+')
|
11
|
+
end
|
12
|
+
|
13
|
+
# URL-decode a string with encoding(optional).
|
14
|
+
# string = CGI::unescape("%27Stop%21%27+said+Fred")
|
15
|
+
# # => "'Stop!' said Fred"
|
16
|
+
def CGI::unescape(string,encoding=@@accept_charset)
|
17
|
+
str=string.tr('+', ' ').force_encoding(Encoding::ASCII_8BIT).gsub(/((?:%[0-9a-fA-F]{2})+)/) do
|
18
|
+
[$1.delete('%')].pack('H*')
|
19
|
+
end.force_encoding(encoding)
|
20
|
+
str.valid_encoding? ? str : str.force_encoding(string.encoding)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
class Date
|
2
|
+
def self.gregorian_leap?(year)
|
3
|
+
if year % 400 == 0
|
4
|
+
true
|
5
|
+
elsif year % 100 == 0 then
|
6
|
+
false
|
7
|
+
elsif year % 4 == 0 then
|
8
|
+
true
|
9
|
+
else
|
10
|
+
false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(year = nil, month = nil, day = nil)
|
15
|
+
if year && month && day
|
16
|
+
@value = Time.utc(year, month, day)
|
17
|
+
else
|
18
|
+
@value = Time.now
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.today
|
23
|
+
new
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
"#{year}-#{month}-#{day}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def ==(other)
|
31
|
+
year == other.year &&
|
32
|
+
month == other.month &&
|
33
|
+
day == other.day
|
34
|
+
end
|
35
|
+
|
36
|
+
def +(other)
|
37
|
+
val = @value + other * 3600 * 24
|
38
|
+
Date.new(val.year, val.month, val.day)
|
39
|
+
end
|
40
|
+
|
41
|
+
def -(other)
|
42
|
+
if other.is_a?(Date)
|
43
|
+
(@value - other.instance_variable_get(:@value)) / (3600 * 24)
|
44
|
+
elsif other.is_a?(Time)
|
45
|
+
(@value - other)
|
46
|
+
else
|
47
|
+
self + (-other)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def >>(months)
|
52
|
+
new_year = year + (self.month + months - 1) / 12
|
53
|
+
new_month = (self.month + months) % 12
|
54
|
+
new_month = new_month == 0 ? 12 : new_month
|
55
|
+
new_day = [day, Time.days_in_month(new_month, new_year)].min
|
56
|
+
|
57
|
+
Date.new(new_year, new_month, new_day)
|
58
|
+
end
|
59
|
+
|
60
|
+
def <<(months)
|
61
|
+
return self >> -months
|
62
|
+
end
|
63
|
+
|
64
|
+
[:year, :month, :day, :wday, :<, :<=, :>, :>=, :"<=>", :strftime].each do |method|
|
65
|
+
define_method method do |*args|
|
66
|
+
@value.send(method, *args)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_date
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_time
|
75
|
+
@value
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Time
|
2
|
+
def to_date
|
3
|
+
Date.new(year, month, day)
|
4
|
+
end
|
5
|
+
|
6
|
+
def to_time
|
7
|
+
self
|
8
|
+
end
|
9
|
+
|
10
|
+
def ==(other)
|
11
|
+
other &&
|
12
|
+
year == other.year &&
|
13
|
+
month == other.month &&
|
14
|
+
day == other.day &&
|
15
|
+
hour == other.hour &&
|
16
|
+
min == other.min &&
|
17
|
+
sec == other.sec
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Array
|
2
|
+
# Returns the tail of the array from +position+.
|
3
|
+
#
|
4
|
+
# %w( a b c d ).from(0) # => ["a", "b", "c", "d"]
|
5
|
+
# %w( a b c d ).from(2) # => ["c", "d"]
|
6
|
+
# %w( a b c d ).from(10) # => []
|
7
|
+
# %w().from(0) # => []
|
8
|
+
def from(position)
|
9
|
+
self[position, length] || []
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns the beginning of the array up to +position+.
|
13
|
+
#
|
14
|
+
# %w( a b c d ).to(0) # => ["a"]
|
15
|
+
# %w( a b c d ).to(2) # => ["a", "b", "c"]
|
16
|
+
# %w( a b c d ).to(10) # => ["a", "b", "c", "d"]
|
17
|
+
# %w().to(0) # => []
|
18
|
+
def to(position)
|
19
|
+
first position + 1
|
20
|
+
end
|
21
|
+
|
22
|
+
# Equal to <tt>self[1]</tt>.
|
23
|
+
#
|
24
|
+
# %w( a b c d e ).second # => "b"
|
25
|
+
def second
|
26
|
+
self[1]
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
class Array
|
2
|
+
# Converts the array to a comma-separated sentence where the last element is
|
3
|
+
# joined by the connector word.
|
4
|
+
#
|
5
|
+
# You can pass the following options to change the default behavior. If you
|
6
|
+
# pass an option key that doesn't exist in the list below, it will raise an
|
7
|
+
# <tt>ArgumentError</tt>.
|
8
|
+
#
|
9
|
+
# Options:
|
10
|
+
#
|
11
|
+
# * <tt>:words_connector</tt> - The sign or word used to join the elements
|
12
|
+
# in arrays with two or more elements (default: ", ").
|
13
|
+
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements
|
14
|
+
# in arrays with two elements (default: " and ").
|
15
|
+
# * <tt>:last_word_connector</tt> - The sign or word used to join the last element
|
16
|
+
# in arrays with three or more elements (default: ", and ").
|
17
|
+
#
|
18
|
+
# [].to_sentence # => ""
|
19
|
+
# ['one'].to_sentence # => "one"
|
20
|
+
# ['one', 'two'].to_sentence # => "one and two"
|
21
|
+
# ['one', 'two', 'three'].to_sentence # => "one, two, and three"
|
22
|
+
#
|
23
|
+
# ['one', 'two'].to_sentence(passing: 'invalid option')
|
24
|
+
# # => ArgumentError: Unknown key :passing
|
25
|
+
#
|
26
|
+
# ['one', 'two'].to_sentence(two_words_connector: '-')
|
27
|
+
# # => "one-two"
|
28
|
+
#
|
29
|
+
# ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ')
|
30
|
+
# # => "one or two or at least three"
|
31
|
+
def to_sentence(options = {})
|
32
|
+
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector)
|
33
|
+
|
34
|
+
default_connectors = {
|
35
|
+
:words_connector => ', ',
|
36
|
+
:two_words_connector => ' and ',
|
37
|
+
:last_word_connector => ', and '
|
38
|
+
}
|
39
|
+
options = default_connectors.merge!(options)
|
40
|
+
|
41
|
+
case length
|
42
|
+
when 0
|
43
|
+
''
|
44
|
+
when 1
|
45
|
+
self[0].to_s.dup
|
46
|
+
when 2
|
47
|
+
"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
|
48
|
+
else
|
49
|
+
"#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Converts a collection of elements into a formatted string by calling
|
54
|
+
# <tt>to_s</tt> on all elements and joining them. Having this model:
|
55
|
+
#
|
56
|
+
# class Blog < ActiveRecord::Base
|
57
|
+
# def to_s
|
58
|
+
# title
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# Blog.all.map(&:title) #=> ["First Post", "Second Post", "Third post"]
|
63
|
+
#
|
64
|
+
# <tt>to_formatted_s</tt> shows us:
|
65
|
+
#
|
66
|
+
# Blog.all.to_formatted_s # => "First PostSecond PostThird Post"
|
67
|
+
#
|
68
|
+
# Adding in the <tt>:db</tt> argument as the format yields a comma separated
|
69
|
+
# id list:
|
70
|
+
#
|
71
|
+
# Blog.all.to_formatted_s(:db) # => "1,2,3"
|
72
|
+
def to_formatted_s(format = :default)
|
73
|
+
case format
|
74
|
+
when :db
|
75
|
+
if empty?
|
76
|
+
'null'
|
77
|
+
else
|
78
|
+
collect { |element| element.id }.join(',')
|
79
|
+
end
|
80
|
+
else
|
81
|
+
to_default_s
|
82
|
+
end
|
83
|
+
end
|
84
|
+
alias_method :to_default_s, :to_s
|
85
|
+
alias_method :to_s, :to_formatted_s
|
86
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
class Array
|
2
|
+
# Splits or iterates over the array in groups of size +number+,
|
3
|
+
# padding any remaining slots with +fill_with+ unless it is +false+.
|
4
|
+
#
|
5
|
+
# %w(1 2 3 4 5 6 7 8 9 10).in_groups_of(3) {|group| p group}
|
6
|
+
# ["1", "2", "3"]
|
7
|
+
# ["4", "5", "6"]
|
8
|
+
# ["7", "8", "9"]
|
9
|
+
# ["10", nil, nil]
|
10
|
+
#
|
11
|
+
# %w(1 2 3 4 5).in_groups_of(2, ' ') {|group| p group}
|
12
|
+
# ["1", "2"]
|
13
|
+
# ["3", "4"]
|
14
|
+
# ["5", " "]
|
15
|
+
#
|
16
|
+
# %w(1 2 3 4 5).in_groups_of(2, false) {|group| p group}
|
17
|
+
# ["1", "2"]
|
18
|
+
# ["3", "4"]
|
19
|
+
# ["5"]
|
20
|
+
def in_groups_of(number, fill_with = nil)
|
21
|
+
if fill_with == false
|
22
|
+
collection = self
|
23
|
+
else
|
24
|
+
# size % number gives how many extra we have;
|
25
|
+
# subtracting from number gives how many to add;
|
26
|
+
# modulo number ensures we don't add group of just fill.
|
27
|
+
padding = (number - size % number) % number
|
28
|
+
collection = dup.concat([fill_with] * padding)
|
29
|
+
end
|
30
|
+
|
31
|
+
if block_given?
|
32
|
+
collection.each_slice(number) { |slice| yield(slice) }
|
33
|
+
else
|
34
|
+
groups = []
|
35
|
+
collection.each_slice(number) { |group| groups << group }
|
36
|
+
groups
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Splits or iterates over the array in +number+ of groups, padding any
|
41
|
+
# remaining slots with +fill_with+ unless it is +false+.
|
42
|
+
#
|
43
|
+
# %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group}
|
44
|
+
# ["1", "2", "3", "4"]
|
45
|
+
# ["5", "6", "7", nil]
|
46
|
+
# ["8", "9", "10", nil]
|
47
|
+
#
|
48
|
+
# %w(1 2 3 4 5 6 7 8 9 10).in_groups(3, ' ') {|group| p group}
|
49
|
+
# ["1", "2", "3", "4"]
|
50
|
+
# ["5", "6", "7", " "]
|
51
|
+
# ["8", "9", "10", " "]
|
52
|
+
#
|
53
|
+
# %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
|
54
|
+
# ["1", "2", "3"]
|
55
|
+
# ["4", "5"]
|
56
|
+
# ["6", "7"]
|
57
|
+
def in_groups(number, fill_with = nil)
|
58
|
+
# size / number gives minor group size;
|
59
|
+
# size % number gives how many objects need extra accommodation;
|
60
|
+
# each group hold either division or division + 1 items.
|
61
|
+
division = size.div number
|
62
|
+
modulo = size % number
|
63
|
+
|
64
|
+
# create a new array avoiding dup
|
65
|
+
groups = []
|
66
|
+
start = 0
|
67
|
+
|
68
|
+
number.times do |index|
|
69
|
+
length = division + (modulo > 0 && modulo > index ? 1 : 0)
|
70
|
+
groups << last_group = slice(start, length)
|
71
|
+
last_group << fill_with if fill_with != false &&
|
72
|
+
modulo > 0 && length == division
|
73
|
+
start += length
|
74
|
+
end
|
75
|
+
|
76
|
+
if block_given?
|
77
|
+
groups.each { |g| yield(g) }
|
78
|
+
else
|
79
|
+
groups
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Divides the array into one or more subarrays based on a delimiting +value+
|
84
|
+
# or the result of an optional block.
|
85
|
+
#
|
86
|
+
# [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
|
87
|
+
# (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
|
88
|
+
def split(value = nil, &block)
|
89
|
+
inject([[]]) do |results, element|
|
90
|
+
if block && block.call(element) || value == element
|
91
|
+
results << []
|
92
|
+
else
|
93
|
+
results.last << element
|
94
|
+
end
|
95
|
+
|
96
|
+
results
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class Array
|
2
|
+
# Wraps its argument in an array unless it is already an array (or array-like).
|
3
|
+
#
|
4
|
+
# Specifically:
|
5
|
+
#
|
6
|
+
# * If the argument is +nil+ an empty list is returned.
|
7
|
+
# * Otherwise, if the argument responds to +to_ary+ it is invoked, and its result returned.
|
8
|
+
# * Otherwise, returns an array with the argument as its single element.
|
9
|
+
#
|
10
|
+
# Array.wrap(nil) # => []
|
11
|
+
# Array.wrap([1, 2, 3]) # => [1, 2, 3]
|
12
|
+
# Array.wrap(0) # => [0]
|
13
|
+
#
|
14
|
+
# This method is similar in purpose to <tt>Kernel#Array</tt>, but there are some differences:
|
15
|
+
#
|
16
|
+
# * If the argument responds to +to_ary+ the method is invoked. <tt>Kernel#Array</tt>
|
17
|
+
# moves on to try +to_a+ if the returned value is +nil+, but <tt>Array.wrap</tt> returns
|
18
|
+
# such a +nil+ right away.
|
19
|
+
# * If the returned value from +to_ary+ is neither +nil+ nor an +Array+ object, <tt>Kernel#Array</tt>
|
20
|
+
# raises an exception, while <tt>Array.wrap</tt> does not, it just returns the value.
|
21
|
+
# * It does not call +to_a+ on the argument, though special-cases +nil+ to return an empty array.
|
22
|
+
#
|
23
|
+
# The last point is particularly worth comparing for some enumerables:
|
24
|
+
#
|
25
|
+
# Array(foo: :bar) # => [[:foo, :bar]]
|
26
|
+
# Array.wrap(foo: :bar) # => [{:foo=>:bar}]
|
27
|
+
#
|
28
|
+
# There's also a related idiom that uses the splat operator:
|
29
|
+
#
|
30
|
+
# [*object]
|
31
|
+
#
|
32
|
+
# which for +nil+ returns <tt>[]</tt>, and calls to <tt>Array(object)</tt> otherwise.
|
33
|
+
#
|
34
|
+
# Thus, in this case the behavior may be different for +nil+, and the differences with
|
35
|
+
# <tt>Kernel#Array</tt> explained above apply to the rest of <tt>object</tt>s.
|
36
|
+
def self.wrap(object)
|
37
|
+
if object.nil?
|
38
|
+
[]
|
39
|
+
elsif object.respond_to?(:to_ary)
|
40
|
+
object.to_ary || [object]
|
41
|
+
else
|
42
|
+
[object]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|