motion-support 0.1.0 → 0.2.0

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.
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)