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.
Files changed (171) hide show
  1. data/.gitignore +3 -0
  2. data/Gemfile +1 -1
  3. data/README.md +231 -2
  4. data/Rakefile +3 -3
  5. data/app/app_delegate.rb +0 -2
  6. data/examples/Inflector/.gitignore +16 -0
  7. data/examples/Inflector/Gemfile +5 -0
  8. data/examples/Inflector/Rakefile +13 -0
  9. data/examples/Inflector/app/app_delegate.rb +8 -0
  10. data/examples/Inflector/app/inflections.rb +5 -0
  11. data/examples/Inflector/app/inflector_view_controller.rb +120 -0
  12. data/examples/Inflector/app/words_view_controller.rb +101 -0
  13. data/examples/Inflector/resources/Default-568h@2x.png +0 -0
  14. data/examples/Inflector/spec/main_spec.rb +9 -0
  15. data/lib/motion-support/core_ext/array.rb +13 -0
  16. data/lib/motion-support/core_ext/class.rb +8 -0
  17. data/lib/motion-support/core_ext/hash.rb +16 -0
  18. data/lib/motion-support/core_ext/integer.rb +9 -0
  19. data/lib/motion-support/core_ext/module.rb +14 -0
  20. data/lib/motion-support/core_ext/numeric.rb +8 -0
  21. data/lib/motion-support/core_ext/object.rb +14 -0
  22. data/lib/motion-support/core_ext/range.rb +8 -0
  23. data/lib/motion-support/core_ext/string.rb +14 -0
  24. data/lib/motion-support/core_ext/time.rb +19 -0
  25. data/lib/motion-support/core_ext.rb +3 -0
  26. data/lib/motion-support/inflector.rb +12 -156
  27. data/lib/motion-support.rb +5 -5
  28. data/motion/_stdlib/cgi.rb +22 -0
  29. data/motion/_stdlib/date.rb +77 -0
  30. data/motion/_stdlib/time.rb +19 -0
  31. data/motion/core_ext/array/access.rb +28 -0
  32. data/motion/core_ext/array/conversions.rb +86 -0
  33. data/motion/core_ext/array/extract_options.rb +11 -0
  34. data/motion/core_ext/array/grouping.rb +99 -0
  35. data/motion/core_ext/array/prepend_and_append.rb +7 -0
  36. data/motion/core_ext/array/wrap.rb +45 -0
  37. data/{lib/motion-support → motion/core_ext}/array.rb +0 -4
  38. data/motion/core_ext/class/attribute.rb +119 -0
  39. data/motion/core_ext/class/attribute_accessors.rb +168 -0
  40. data/motion/core_ext/date/acts_like.rb +8 -0
  41. data/motion/core_ext/date/calculations.rb +117 -0
  42. data/motion/core_ext/date/conversions.rb +56 -0
  43. data/motion/core_ext/date_and_time/calculations.rb +232 -0
  44. data/motion/core_ext/enumerable.rb +90 -0
  45. data/motion/core_ext/hash/deep_merge.rb +27 -0
  46. data/motion/core_ext/hash/except.rb +15 -0
  47. data/motion/core_ext/hash/indifferent_access.rb +19 -0
  48. data/motion/core_ext/hash/keys.rb +138 -0
  49. data/motion/core_ext/hash/reverse_merge.rb +22 -0
  50. data/motion/core_ext/hash/slice.rb +40 -0
  51. data/motion/core_ext/integer/inflections.rb +27 -0
  52. data/motion/core_ext/integer/multiple.rb +10 -0
  53. data/motion/core_ext/integer/time.rb +41 -0
  54. data/{lib/motion-support → motion/core_ext}/metaclass.rb +0 -0
  55. data/motion/core_ext/module/aliasing.rb +69 -0
  56. data/motion/core_ext/module/anonymous.rb +19 -0
  57. data/motion/core_ext/module/attr_internal.rb +38 -0
  58. data/motion/core_ext/module/attribute_accessors.rb +64 -0
  59. data/motion/core_ext/module/delegation.rb +175 -0
  60. data/motion/core_ext/module/introspection.rb +60 -0
  61. data/motion/core_ext/module/reachable.rb +5 -0
  62. data/motion/core_ext/module/remove_method.rb +12 -0
  63. data/motion/core_ext/ns_dictionary.rb +11 -0
  64. data/motion/core_ext/numeric/bytes.rb +44 -0
  65. data/motion/core_ext/numeric/conversions.rb +7 -0
  66. data/motion/core_ext/numeric/time.rb +75 -0
  67. data/motion/core_ext/object/acts_like.rb +10 -0
  68. data/motion/core_ext/object/blank.rb +105 -0
  69. data/motion/core_ext/object/deep_dup.rb +44 -0
  70. data/motion/core_ext/object/duplicable.rb +83 -0
  71. data/motion/core_ext/object/instance_variables.rb +28 -0
  72. data/motion/core_ext/object/to_param.rb +58 -0
  73. data/motion/core_ext/object/to_query.rb +26 -0
  74. data/motion/core_ext/object/try.rb +78 -0
  75. data/motion/core_ext/range/include_range.rb +23 -0
  76. data/motion/core_ext/range/overlaps.rb +8 -0
  77. data/motion/core_ext/regexp.rb +5 -0
  78. data/motion/core_ext/string/access.rb +104 -0
  79. data/motion/core_ext/string/behavior.rb +6 -0
  80. data/motion/core_ext/string/exclude.rb +11 -0
  81. data/motion/core_ext/string/filters.rb +55 -0
  82. data/motion/core_ext/string/indent.rb +43 -0
  83. data/motion/core_ext/string/inflections.rb +195 -0
  84. data/motion/core_ext/string/starts_ends_with.rb +4 -0
  85. data/motion/core_ext/string/strip.rb +24 -0
  86. data/motion/core_ext/time/acts_like.rb +8 -0
  87. data/motion/core_ext/time/calculations.rb +215 -0
  88. data/motion/core_ext/time/conversions.rb +52 -0
  89. data/motion/duration.rb +104 -0
  90. data/motion/hash_with_indifferent_access.rb +251 -0
  91. data/motion/inflections.rb +67 -0
  92. data/motion/inflector/inflections.rb +203 -0
  93. data/motion/inflector/methods.rb +321 -0
  94. data/{lib/motion-support → motion}/logger.rb +0 -0
  95. data/{lib/motion-support → motion}/version.rb +1 -1
  96. data/motion-support.gemspec +2 -2
  97. data/spec/motion-support/_helpers/constantize_test_cases.rb +75 -0
  98. data/spec/motion-support/_helpers/inflector_test_cases.rb +313 -0
  99. data/spec/motion-support/core_ext/array/access_spec.rb +29 -0
  100. data/spec/motion-support/core_ext/array/conversion_spec.rb +60 -0
  101. data/spec/motion-support/core_ext/array/extract_options_spec.rb +15 -0
  102. data/spec/motion-support/core_ext/array/grouping_spec.rb +85 -0
  103. data/spec/motion-support/core_ext/array/prepend_and_append_spec.rb +25 -0
  104. data/spec/motion-support/core_ext/array/wrap_spec.rb +19 -0
  105. data/spec/motion-support/{array_spec.rb → core_ext/array_spec.rb} +0 -5
  106. data/spec/motion-support/core_ext/class/attribute_accessor_spec.rb +127 -0
  107. data/spec/motion-support/core_ext/class/attribute_spec.rb +92 -0
  108. data/spec/motion-support/core_ext/date/acts_like_spec.rb +11 -0
  109. data/spec/motion-support/core_ext/date/calculation_spec.rb +186 -0
  110. data/spec/motion-support/core_ext/date/conversion_spec.rb +18 -0
  111. data/spec/motion-support/core_ext/date_and_time/calculation_spec.rb +336 -0
  112. data/spec/motion-support/core_ext/enumerable_spec.rb +130 -0
  113. data/spec/motion-support/core_ext/hash/deep_merge_spec.rb +32 -0
  114. data/spec/motion-support/core_ext/hash/except_spec.rb +43 -0
  115. data/spec/motion-support/core_ext/hash/key_spec.rb +230 -0
  116. data/spec/motion-support/core_ext/hash/reverse_merge_spec.rb +26 -0
  117. data/spec/motion-support/core_ext/hash/slice_spec.rb +61 -0
  118. data/spec/motion-support/core_ext/integer/inflection_spec.rb +23 -0
  119. data/spec/motion-support/core_ext/integer/multiple_spec.rb +19 -0
  120. data/spec/motion-support/{metaclass_spec.rb → core_ext/metaclass_spec.rb} +0 -0
  121. data/spec/motion-support/core_ext/module/aliasing_spec.rb +143 -0
  122. data/spec/motion-support/core_ext/module/anonymous_spec.rb +29 -0
  123. data/spec/motion-support/core_ext/module/attr_internal_spec.rb +104 -0
  124. data/spec/motion-support/core_ext/module/attribute_accessor_spec.rb +86 -0
  125. data/spec/motion-support/core_ext/module/delegation_spec.rb +136 -0
  126. data/spec/motion-support/core_ext/module/introspection_spec.rb +70 -0
  127. data/spec/motion-support/core_ext/module/reachable_spec.rb +61 -0
  128. data/spec/motion-support/core_ext/module/remove_method_spec.rb +25 -0
  129. data/spec/motion-support/core_ext/numeric/bytes_spec.rb +43 -0
  130. data/spec/motion-support/core_ext/object/acts_like_spec.rb +21 -0
  131. data/spec/motion-support/core_ext/object/blank_spec.rb +54 -0
  132. data/spec/motion-support/core_ext/object/deep_dup_spec.rb +54 -0
  133. data/spec/motion-support/core_ext/object/duplicable_spec.rb +31 -0
  134. data/spec/motion-support/core_ext/object/instance_variable_spec.rb +19 -0
  135. data/spec/motion-support/core_ext/object/to_param_spec.rb +75 -0
  136. data/spec/motion-support/core_ext/object/to_query_spec.rb +37 -0
  137. data/spec/motion-support/core_ext/object/try_spec.rb +92 -0
  138. data/spec/motion-support/core_ext/range/include_range_spec.rb +31 -0
  139. data/spec/motion-support/core_ext/range/overlap_spec.rb +43 -0
  140. data/spec/motion-support/core_ext/regexp_spec.rb +7 -0
  141. data/spec/motion-support/core_ext/string/access_spec.rb +53 -0
  142. data/spec/motion-support/core_ext/string/behavior_spec.rb +7 -0
  143. data/spec/motion-support/core_ext/string/exclude_spec.rb +8 -0
  144. data/spec/motion-support/core_ext/string/filter_spec.rb +48 -0
  145. data/spec/motion-support/core_ext/string/indent_spec.rb +56 -0
  146. data/spec/motion-support/core_ext/string/inflection_spec.rb +142 -0
  147. data/spec/motion-support/core_ext/string/starts_end_with_spec.rb +14 -0
  148. data/spec/motion-support/core_ext/string/strip_spec.rb +34 -0
  149. data/spec/motion-support/core_ext/string_spec.rb +88 -0
  150. data/spec/motion-support/core_ext/time/acts_like_spec.rb +11 -0
  151. data/spec/motion-support/core_ext/time/calculation_spec.rb +201 -0
  152. data/spec/motion-support/core_ext/time/conversion_spec.rb +54 -0
  153. data/spec/motion-support/duration_spec.rb +107 -0
  154. data/spec/motion-support/hash_with_indifferent_access_spec.rb +605 -0
  155. data/spec/motion-support/inflector_spec.rb +474 -35
  156. data/spec/motion-support/ns_dictionary_spec.rb +29 -0
  157. metadata +212 -35
  158. data/lib/motion-support/cattr_accessor.rb +0 -19
  159. data/lib/motion-support/class_inheritable_accessor.rb +0 -23
  160. data/lib/motion-support/class_inheritable_array.rb +0 -29
  161. data/lib/motion-support/hash.rb +0 -31
  162. data/lib/motion-support/nilclass.rb +0 -5
  163. data/lib/motion-support/object.rb +0 -17
  164. data/lib/motion-support/string.rb +0 -71
  165. data/spec/motion-support/cattr_accessor_spec.rb +0 -49
  166. data/spec/motion-support/class_inheritable_accessor_spec.rb +0 -49
  167. data/spec/motion-support/class_inheritable_array_spec.rb +0 -61
  168. data/spec/motion-support/hash_spec.rb +0 -31
  169. data/spec/motion-support/nilclass_spec.rb +0 -5
  170. data/spec/motion-support/object_spec.rb +0 -43
  171. 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)
@@ -0,0 +1,3 @@
1
+ Dir["#{File.dirname(__FILE__)}/core_ext/*.rb"].sort.each do |path|
2
+ require path
3
+ end
@@ -1,156 +1,12 @@
1
- # Inflector is a singleton class that helps
2
- # singularize, pluralize and other-thing-ize
3
- # words. It is very much based on the Rails
4
- # ActiveSupport implementation or Inflector
5
- class Inflector
6
- def self.instance #nodoc
7
- @__instance__ ||= new
8
- end
9
-
10
- def initialize #nodoc
11
- reset
12
- end
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)
@@ -1,5 +1,5 @@
1
- require "motion-support/version"
2
- require 'bubble-wrap'
3
- Dir.glob(File.join(File.dirname(__FILE__), 'motion-support/*.rb')).each do |file|
4
- BW.require file
5
- end
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,11 @@
1
+ class Array
2
+ # Extracts options from a set of arguments. Removes and returns the last
3
+ # element in the array if it's a hash, otherwise returns a blank hash.
4
+ def extract_options!
5
+ if last.is_a?(Hash)
6
+ pop
7
+ else
8
+ {}
9
+ end
10
+ end
11
+ 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, '&nbsp;') {|group| p group}
12
+ # ["1", "2"]
13
+ # ["3", "4"]
14
+ # ["5", "&nbsp;"]
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, '&nbsp;') {|group| p group}
49
+ # ["1", "2", "3", "4"]
50
+ # ["5", "6", "7", "&nbsp;"]
51
+ # ["8", "9", "10", "&nbsp;"]
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,7 @@
1
+ class Array
2
+ # The human way of thinking about adding stuff to the end of a list is with append
3
+ alias_method :append, :<<
4
+
5
+ # The human way of thinking about adding stuff to the beginning of a list is with prepend
6
+ alias_method :prepend, :unshift
7
+ 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
@@ -1,8 +1,4 @@
1
1
  class Array
2
- def empty?
3
- self.length < 1
4
- end
5
-
6
2
  # If any item in the array has the key == `key` true, otherwise false.
7
3
  # Of good use when writing specs.
8
4
  def has_hash_key?(key)