activesupport-refinements 0.0.1

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 (120) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +6 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +32 -0
  5. data/Rakefile +1 -0
  6. data/activesupport-refinements.gemspec +21 -0
  7. data/lib/active_support/refinements/core_ext/array.rb +7 -0
  8. data/lib/active_support/refinements/core_ext/array/access.rb +56 -0
  9. data/lib/active_support/refinements/core_ext/array/conversions.rb +224 -0
  10. data/lib/active_support/refinements/core_ext/array/extract_options.rb +31 -0
  11. data/lib/active_support/refinements/core_ext/array/grouping.rb +101 -0
  12. data/lib/active_support/refinements/core_ext/array/prepend_and_append.rb +9 -0
  13. data/lib/active_support/refinements/core_ext/array/uniq_by.rb +21 -0
  14. data/lib/active_support/refinements/core_ext/array/wrap.rb +48 -0
  15. data/lib/active_support/refinements/core_ext/benchmark.rb +7 -0
  16. data/lib/active_support/refinements/core_ext/big_decimal.rb +1 -0
  17. data/lib/active_support/refinements/core_ext/big_decimal/conversions.rb +32 -0
  18. data/lib/active_support/refinements/core_ext/class.rb +4 -0
  19. data/lib/active_support/refinements/core_ext/class/attribute.rb +119 -0
  20. data/lib/active_support/refinements/core_ext/class/attribute_accessors.rb +172 -0
  21. data/lib/active_support/refinements/core_ext/class/delegating_attributes.rb +42 -0
  22. data/lib/active_support/refinements/core_ext/class/subclasses.rb +44 -0
  23. data/lib/active_support/refinements/core_ext/date.rb +5 -0
  24. data/lib/active_support/refinements/core_ext/date/acts_like.rb +10 -0
  25. data/lib/active_support/refinements/core_ext/date/calculations.rb +123 -0
  26. data/lib/active_support/refinements/core_ext/date/conversions.rb +86 -0
  27. data/lib/active_support/refinements/core_ext/date/zones.rb +17 -0
  28. data/lib/active_support/refinements/core_ext/date_and_time/calculations.rb +232 -0
  29. data/lib/active_support/refinements/core_ext/date_time.rb +4 -0
  30. data/lib/active_support/refinements/core_ext/date_time/acts_like.rb +15 -0
  31. data/lib/active_support/refinements/core_ext/date_time/calculations.rb +143 -0
  32. data/lib/active_support/refinements/core_ext/date_time/conversions.rb +93 -0
  33. data/lib/active_support/refinements/core_ext/date_time/zones.rb +26 -0
  34. data/lib/active_support/refinements/core_ext/enumerable.rb +82 -0
  35. data/lib/active_support/refinements/core_ext/exception.rb +5 -0
  36. data/lib/active_support/refinements/core_ext/file.rb +1 -0
  37. data/lib/active_support/refinements/core_ext/file/atomic.rb +60 -0
  38. data/lib/active_support/refinements/core_ext/hash.rb +8 -0
  39. data/lib/active_support/refinements/core_ext/hash/conversions.rb +161 -0
  40. data/lib/active_support/refinements/core_ext/hash/deep_merge.rb +29 -0
  41. data/lib/active_support/refinements/core_ext/hash/diff.rb +15 -0
  42. data/lib/active_support/refinements/core_ext/hash/except.rb +17 -0
  43. data/lib/active_support/refinements/core_ext/hash/indifferent_access.rb +24 -0
  44. data/lib/active_support/refinements/core_ext/hash/keys.rb +140 -0
  45. data/lib/active_support/refinements/core_ext/hash/reverse_merge.rb +24 -0
  46. data/lib/active_support/refinements/core_ext/hash/slice.rb +42 -0
  47. data/lib/active_support/refinements/core_ext/integer.rb +3 -0
  48. data/lib/active_support/refinements/core_ext/integer/inflections.rb +31 -0
  49. data/lib/active_support/refinements/core_ext/integer/multiple.rb +12 -0
  50. data/lib/active_support/refinements/core_ext/integer/time.rb +43 -0
  51. data/lib/active_support/refinements/core_ext/kernel.rb +4 -0
  52. data/lib/active_support/refinements/core_ext/kernel/agnostics.rb +13 -0
  53. data/lib/active_support/refinements/core_ext/kernel/debugger.rb +12 -0
  54. data/lib/active_support/refinements/core_ext/kernel/reporting.rb +97 -0
  55. data/lib/active_support/refinements/core_ext/kernel/singleton_class.rb +8 -0
  56. data/lib/active_support/refinements/core_ext/load_error.rb +27 -0
  57. data/lib/active_support/refinements/core_ext/logger.rb +86 -0
  58. data/lib/active_support/refinements/core_ext/module.rb +10 -0
  59. data/lib/active_support/refinements/core_ext/module/aliasing.rb +69 -0
  60. data/lib/active_support/refinements/core_ext/module/anonymous.rb +21 -0
  61. data/lib/active_support/refinements/core_ext/module/attr_internal.rb +40 -0
  62. data/lib/active_support/refinements/core_ext/module/attribute_accessors.rb +68 -0
  63. data/lib/active_support/refinements/core_ext/module/delegation.rb +172 -0
  64. data/lib/active_support/refinements/core_ext/module/deprecation.rb +27 -0
  65. data/lib/active_support/refinements/core_ext/module/introspection.rb +80 -0
  66. data/lib/active_support/refinements/core_ext/module/qualified_const.rb +54 -0
  67. data/lib/active_support/refinements/core_ext/module/reachable.rb +10 -0
  68. data/lib/active_support/refinements/core_ext/module/remove_method.rb +14 -0
  69. data/lib/active_support/refinements/core_ext/name_error.rb +20 -0
  70. data/lib/active_support/refinements/core_ext/numeric.rb +3 -0
  71. data/lib/active_support/refinements/core_ext/numeric/bytes.rb +46 -0
  72. data/lib/active_support/refinements/core_ext/numeric/conversions.rb +137 -0
  73. data/lib/active_support/refinements/core_ext/numeric/time.rb +81 -0
  74. data/lib/active_support/refinements/core_ext/object.rb +14 -0
  75. data/lib/active_support/refinements/core_ext/object/acts_like.rb +12 -0
  76. data/lib/active_support/refinements/core_ext/object/blank.rb +107 -0
  77. data/lib/active_support/refinements/core_ext/object/conversions.rb +4 -0
  78. data/lib/active_support/refinements/core_ext/object/deep_dup.rb +48 -0
  79. data/lib/active_support/refinements/core_ext/object/duplicable.rb +92 -0
  80. data/lib/active_support/refinements/core_ext/object/inclusion.rb +27 -0
  81. data/lib/active_support/refinements/core_ext/object/instance_variables.rb +30 -0
  82. data/lib/active_support/refinements/core_ext/object/to_json.rb +27 -0
  83. data/lib/active_support/refinements/core_ext/object/to_param.rb +60 -0
  84. data/lib/active_support/refinements/core_ext/object/to_query.rb +29 -0
  85. data/lib/active_support/refinements/core_ext/object/try.rb +72 -0
  86. data/lib/active_support/refinements/core_ext/object/with_options.rb +44 -0
  87. data/lib/active_support/refinements/core_ext/proc.rb +19 -0
  88. data/lib/active_support/refinements/core_ext/range.rb +3 -0
  89. data/lib/active_support/refinements/core_ext/range/conversions.rb +21 -0
  90. data/lib/active_support/refinements/core_ext/range/include_range.rb +23 -0
  91. data/lib/active_support/refinements/core_ext/range/overlaps.rb +10 -0
  92. data/lib/active_support/refinements/core_ext/regexp.rb +7 -0
  93. data/lib/active_support/refinements/core_ext/string.rb +13 -0
  94. data/lib/active_support/refinements/core_ext/string/access.rb +106 -0
  95. data/lib/active_support/refinements/core_ext/string/behavior.rb +8 -0
  96. data/lib/active_support/refinements/core_ext/string/conversions.rb +60 -0
  97. data/lib/active_support/refinements/core_ext/string/encoding.rb +10 -0
  98. data/lib/active_support/refinements/core_ext/string/exclude.rb +13 -0
  99. data/lib/active_support/refinements/core_ext/string/filters.rb +54 -0
  100. data/lib/active_support/refinements/core_ext/string/indent.rb +45 -0
  101. data/lib/active_support/refinements/core_ext/string/inflections.rb +214 -0
  102. data/lib/active_support/refinements/core_ext/string/inquiry.rb +15 -0
  103. data/lib/active_support/refinements/core_ext/string/multibyte.rb +58 -0
  104. data/lib/active_support/refinements/core_ext/string/output_safety.rb +194 -0
  105. data/lib/active_support/refinements/core_ext/string/starts_ends_with.rb +6 -0
  106. data/lib/active_support/refinements/core_ext/string/strip.rb +28 -0
  107. data/lib/active_support/refinements/core_ext/string/xchar.rb +18 -0
  108. data/lib/active_support/refinements/core_ext/time.rb +5 -0
  109. data/lib/active_support/refinements/core_ext/time/acts_like.rb +10 -0
  110. data/lib/active_support/refinements/core_ext/time/calculations.rb +251 -0
  111. data/lib/active_support/refinements/core_ext/time/conversions.rb +65 -0
  112. data/lib/active_support/refinements/core_ext/time/marshal.rb +30 -0
  113. data/lib/active_support/refinements/core_ext/time/zones.rb +98 -0
  114. data/lib/active_support/refinements/core_ext/uri.rb +28 -0
  115. data/lib/activesupport-refinements.rb +9 -0
  116. data/lib/activesupport-refinements/version.rb +5 -0
  117. data/refine_core_ext.rb +45 -0
  118. data/spec/hwia_spec.rb +15 -0
  119. data/spec/try_spec.rb +18 -0
  120. metadata +182 -0
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in activesupport-refinements.gemspec
4
+ gemspec
5
+
6
+ gem 'activesupport', path: '~/src/rails/activesupport'
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Akira Matsuda
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,32 @@
1
+ # ActiveSupport::Refinements
2
+
3
+ ActiveSupport + Ruby 2.0 Refinements
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'activesupport-refinements'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install activesupport-refinements
18
+
19
+ ## Usage
20
+
21
+ You can pick some side-effect-free clean core_ext features by requiring 'active_support/refinements/core_ext/**/*' and `using` modules defined there.
22
+ See specs for more details.
23
+
24
+ You can also regenerate newer version of ActiveSupport::Refinements by running `refine_core_ext.rb` script.
25
+
26
+ ## Contributing
27
+
28
+ 1. Fork it
29
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
30
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
31
+ 4. Push to the branch (`git push origin my-new-feature`)
32
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'activesupport-refinements/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "activesupport-refinements"
8
+ gem.version = Activesupport::Refinements::VERSION
9
+ gem.authors = ["Akira Matsuda"]
10
+ gem.email = ["ronnie@dio.jp"]
11
+ gem.description = 'Side-effect-free ActiveSupport using Refinements'
12
+ gem.summary = 'ActiveSupport + Ruby 2.0 refinements'
13
+ gem.homepage = 'https://github.com/amatsuda/activesupport-refinements'
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency 'rspec'
21
+ end
@@ -0,0 +1,7 @@
1
+ require 'active_support/refinements/core_ext/array/wrap'
2
+ require 'active_support/refinements/core_ext/array/access'
3
+ require 'active_support/refinements/core_ext/array/uniq_by'
4
+ require 'active_support/refinements/core_ext/array/conversions'
5
+ require 'active_support/refinements/core_ext/array/extract_options'
6
+ require 'active_support/refinements/core_ext/array/grouping'
7
+ require 'active_support/refinements/core_ext/array/prepend_and_append'
@@ -0,0 +1,56 @@
1
+ module ArrayExt; end; module ArrayExt::Access
2
+ refine Array do
3
+ # Returns the tail of the array from +position+.
4
+ #
5
+ # %w( a b c d ).from(0) # => ["a", "b", "c", "d"]
6
+ # %w( a b c d ).from(2) # => ["c", "d"]
7
+ # %w( a b c d ).from(10) # => []
8
+ # %w().from(0) # => []
9
+ def from(position)
10
+ self[position, length] || []
11
+ end
12
+
13
+ # Returns the beginning of the array up to +position+.
14
+ #
15
+ # %w( a b c d ).to(0) # => ["a"]
16
+ # %w( a b c d ).to(2) # => ["a", "b", "c"]
17
+ # %w( a b c d ).to(10) # => ["a", "b", "c", "d"]
18
+ # %w().to(0) # => []
19
+ def to(position)
20
+ first position + 1
21
+ end
22
+
23
+ # Equal to <tt>self[1]</tt>.
24
+ #
25
+ # %w( a b c d e).second # => "b"
26
+ def second
27
+ self[1]
28
+ end
29
+
30
+ # Equal to <tt>self[2]</tt>.
31
+ #
32
+ # %w( a b c d e).third # => "c"
33
+ def third
34
+ self[2]
35
+ end
36
+
37
+ # Equal to <tt>self[3]</tt>.
38
+ #
39
+ # %w( a b c d e).fourth # => "d"
40
+ def fourth
41
+ self[3]
42
+ end
43
+
44
+ # Equal to <tt>self[4]</tt>.
45
+ #
46
+ # %w( a b c d e).fifth # => "e"
47
+ def fifth
48
+ self[4]
49
+ end
50
+
51
+ # Equal to <tt>self[41]</tt>. Also known as accessing "the reddit".
52
+ def forty_two
53
+ self[41]
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,224 @@
1
+ module ArrayExt; end; module ArrayExt::Conversions
2
+ require 'active_support/xml_mini'
3
+ require 'active_support/refinements/core_ext/hash/keys'
4
+ require 'active_support/refinements/core_ext/string/inflections'
5
+ require 'active_support/refinements/core_ext/object/to_param'
6
+ require 'active_support/refinements/core_ext/object/to_query'
7
+
8
+ refine Array do
9
+ # Converts the array to a comma-separated sentence where the last element is
10
+ # joined by the connector word.
11
+ #
12
+ # You can pass the following options to change the default behaviour. If you
13
+ # pass an option key that doesn't exist in the list below, it will raise an
14
+ # <tt>ArgumentError</tt>.
15
+ #
16
+ # Options:
17
+ #
18
+ # * <tt>:words_connector</tt> - The sign or word used to join the elements
19
+ # in arrays with two or more elements (default: ", ").
20
+ # * <tt>:two_words_connector</tt> - The sign or word used to join the elements
21
+ # in arrays with two elements (default: " and ").
22
+ # * <tt>:last_word_connector</tt> - The sign or word used to join the last element
23
+ # in arrays with three or more elements (default: ", and ").
24
+ # * <tt>:locale</tt> - If +i18n+ is available, you can set a locale and use
25
+ # the connector options defined on the 'support.array' namespace in the
26
+ # corresponding dictionary file.
27
+ #
28
+ # [].to_sentence # => ""
29
+ # ['one'].to_sentence # => "one"
30
+ # ['one', 'two'].to_sentence # => "one and two"
31
+ # ['one', 'two', 'three'].to_sentence # => "one, two, and three"
32
+ #
33
+ # ['one', 'two'].to_sentence(passing: 'invalid option')
34
+ # # => ArgumentError: Unknown key :passing
35
+ #
36
+ # ['one', 'two'].to_sentence(two_words_connector: '-')
37
+ # # => "one-two"
38
+ #
39
+ # ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ')
40
+ # # => "one or two or at least three"
41
+ #
42
+ # Examples using <tt>:locale</tt> option:
43
+ #
44
+ # # Given this locale dictionary:
45
+ # # 
46
+ # # es:
47
+ # # support:
48
+ # # array:
49
+ # # words_connector: " o "
50
+ # # two_words_connector: " y "
51
+ # # last_word_connector: " o al menos "
52
+ #
53
+ # ['uno', 'dos'].to_sentence(locale: :es)
54
+ # # => "uno y dos"
55
+ #
56
+ # ['uno', 'dos', 'tres'].to_sentence(locale: :es)
57
+ # # => "uno o dos o al menos tres"
58
+ def to_sentence(options = {})
59
+ options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
60
+
61
+ default_connectors = {
62
+ :words_connector => ', ',
63
+ :two_words_connector => ' and ',
64
+ :last_word_connector => ', and '
65
+ }
66
+ if defined?(I18n)
67
+ i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {})
68
+ default_connectors.merge!(i18n_connectors)
69
+ end
70
+ options = default_connectors.merge!(options)
71
+
72
+ case length
73
+ when 0
74
+ ''
75
+ when 1
76
+ self[0].to_s.dup
77
+ when 2
78
+ "#{self[0]}#{options[:two_words_connector]}#{self[1]}"
79
+ else
80
+ "#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
81
+ end
82
+ end
83
+
84
+ # Converts a collection of elements into a formatted string by calling
85
+ # <tt>to_s</tt> on all elements and joining them. Having this model:
86
+ #
87
+ # class Blog < ActiveRecord::Base
88
+ # def to_s
89
+ # title
90
+ # end
91
+ # end
92
+ #
93
+ # Blog.all.map(&:title) #=> ["First Post", "Second Post", "Third post"]
94
+ #
95
+ # <tt>to_formatted_s</tt> shows us:
96
+ #
97
+ # Blog.all.to_formatted_s # => "First PostSecond PostThird Post"
98
+ #
99
+ # Adding in the <tt>:db</tt> argument as the format yields a comma separated
100
+ # id list:
101
+ #
102
+ # Blog.all.to_formatted_s(:db) # => "1,2,3"
103
+ def to_formatted_s(format = :default)
104
+ case format
105
+ when :db
106
+ if empty?
107
+ 'null'
108
+ else
109
+ collect { |element| element.id }.join(',')
110
+ end
111
+ else
112
+ to_default_s
113
+ end
114
+ end
115
+ # alias_method :to_default_s, :to_s
116
+ # alias_method :to_s, :to_formatted_s
117
+
118
+ # Returns a string that represents the array in XML by invoking +to_xml+
119
+ # on each element. Active Record collections delegate their representation
120
+ # in XML to this method.
121
+ #
122
+ # All elements are expected to respond to +to_xml+, if any of them does
123
+ # not then an exception is raised.
124
+ #
125
+ # The root node reflects the class name of the first element in plural
126
+ # if all elements belong to the same type and that's not Hash:
127
+ #
128
+ # customer.projects.to_xml
129
+ #
130
+ # <?xml version="1.0" encoding="UTF-8"?>
131
+ # <projects type="array">
132
+ # <project>
133
+ # <amount type="decimal">20000.0</amount>
134
+ # <customer-id type="integer">1567</customer-id>
135
+ # <deal-date type="date">2008-04-09</deal-date>
136
+ # ...
137
+ # </project>
138
+ # <project>
139
+ # <amount type="decimal">57230.0</amount>
140
+ # <customer-id type="integer">1567</customer-id>
141
+ # <deal-date type="date">2008-04-15</deal-date>
142
+ # ...
143
+ # </project>
144
+ # </projects>
145
+ #
146
+ # Otherwise the root element is "objects":
147
+ #
148
+ # [{ foo: 1, bar: 2}, { baz: 3}].to_xml
149
+ #
150
+ # <?xml version="1.0" encoding="UTF-8"?>
151
+ # <objects type="array">
152
+ # <object>
153
+ # <bar type="integer">2</bar>
154
+ # <foo type="integer">1</foo>
155
+ # </object>
156
+ # <object>
157
+ # <baz type="integer">3</baz>
158
+ # </object>
159
+ # </objects>
160
+ #
161
+ # If the collection is empty the root element is "nil-classes" by default:
162
+ #
163
+ # [].to_xml
164
+ #
165
+ # <?xml version="1.0" encoding="UTF-8"?>
166
+ # <nil-classes type="array"/>
167
+ #
168
+ # To ensure a meaningful root element use the <tt>:root</tt> option:
169
+ #
170
+ # customer_with_no_projects.projects.to_xml(root: 'projects')
171
+ #
172
+ # <?xml version="1.0" encoding="UTF-8"?>
173
+ # <projects type="array"/>
174
+ #
175
+ # By default name of the node for the children of root is <tt>root.singularize</tt>.
176
+ # You can change it with the <tt>:children</tt> option.
177
+ #
178
+ # The +options+ hash is passed downwards:
179
+ #
180
+ # Message.all.to_xml(skip_types: true)
181
+ #
182
+ # <?xml version="1.0" encoding="UTF-8"?>
183
+ # <messages>
184
+ # <message>
185
+ # <created-at>2008-03-07T09:58:18+01:00</created-at>
186
+ # <id>1</id>
187
+ # <name>1</name>
188
+ # <updated-at>2008-03-07T09:58:18+01:00</updated-at>
189
+ # <user-id>1</user-id>
190
+ # </message>
191
+ # </messages>
192
+ #
193
+ def to_xml(options = {})
194
+ require 'active_support/builder' unless defined?(Builder)
195
+
196
+ options = options.dup
197
+ options[:indent] ||= 2
198
+ options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
199
+ options[:root] ||= \
200
+ if first.class != Hash && all? { |e| e.is_a?(first.class) }
201
+ underscored = ActiveSupport::Inflector.underscore(first.class.name)
202
+ ActiveSupport::Inflector.pluralize(underscored).tr('/', '_')
203
+ else
204
+ 'objects'
205
+ end
206
+
207
+ builder = options[:builder]
208
+ builder.instruct! unless options.delete(:skip_instruct)
209
+
210
+ root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
211
+ children = options.delete(:children) || root.singularize
212
+ attributes = options[:skip_types] ? {} : {:type => 'array'}
213
+
214
+ if empty?
215
+ builder.tag!(root, attributes)
216
+ else
217
+ builder.__send__(:method_missing, root, attributes) do
218
+ each { |value| ActiveSupport::XmlMini.to_tag(children, value, options) }
219
+ yield builder if block_given?
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,31 @@
1
+ module ArrayExt; end; module ArrayExt::ExtractOptions
2
+ refine Hash do
3
+ # By default, only instances of Hash itself are extractable.
4
+ # Subclasses of Hash may implement this method and return
5
+ # true to declare themselves as extractable. If a Hash
6
+ # is extractable, Array#extract_options! pops it from
7
+ # the Array when it is the last element of the Array.
8
+ def extractable_options?
9
+ instance_of?(Hash)
10
+ end
11
+ end
12
+
13
+ refine Array do
14
+ # Extracts options from a set of arguments. Removes and returns the last
15
+ # element in the array if it's a hash, otherwise returns a blank hash.
16
+ #
17
+ # def options(*args)
18
+ # args.extract_options!
19
+ # end
20
+ #
21
+ # options(1, 2) # => {}
22
+ # options(1, 2, a: :b) # => {:a=>:b}
23
+ def extract_options!
24
+ if last.is_a?(Hash) && last.extractable_options?
25
+ pop
26
+ else
27
+ {}
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,101 @@
1
+ module ArrayExt; end; module ArrayExt::Grouping
2
+ refine Array do
3
+ # Splits or iterates over the array in groups of size +number+,
4
+ # padding any remaining slots with +fill_with+ unless it is +false+.
5
+ #
6
+ # %w(1 2 3 4 5 6 7 8 9 10).in_groups_of(3) {|group| p group}
7
+ # ["1", "2", "3"]
8
+ # ["4", "5", "6"]
9
+ # ["7", "8", "9"]
10
+ # ["10", nil, nil]
11
+ #
12
+ # %w(1 2 3 4 5).in_groups_of(2, '&nbsp;') {|group| p group}
13
+ # ["1", "2"]
14
+ # ["3", "4"]
15
+ # ["5", "&nbsp;"]
16
+ #
17
+ # %w(1 2 3 4 5).in_groups_of(2, false) {|group| p group}
18
+ # ["1", "2"]
19
+ # ["3", "4"]
20
+ # ["5"]
21
+ def in_groups_of(number, fill_with = nil)
22
+ if fill_with == false
23
+ collection = self
24
+ else
25
+ # size % number gives how many extra we have;
26
+ # subtracting from number gives how many to add;
27
+ # modulo number ensures we don't add group of just fill.
28
+ padding = (number - size % number) % number
29
+ collection = dup.concat([fill_with] * padding)
30
+ end
31
+
32
+ if block_given?
33
+ collection.each_slice(number) { |slice| yield(slice) }
34
+ else
35
+ groups = []
36
+ collection.each_slice(number) { |group| groups << group }
37
+ groups
38
+ end
39
+ end
40
+
41
+ # Splits or iterates over the array in +number+ of groups, padding any
42
+ # remaining slots with +fill_with+ unless it is +false+.
43
+ #
44
+ # %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group}
45
+ # ["1", "2", "3", "4"]
46
+ # ["5", "6", "7", nil]
47
+ # ["8", "9", "10", nil]
48
+ #
49
+ # %w(1 2 3 4 5 6 7 8 9 10).in_groups(3, '&nbsp;') {|group| p group}
50
+ # ["1", "2", "3", "4"]
51
+ # ["5", "6", "7", "&nbsp;"]
52
+ # ["8", "9", "10", "&nbsp;"]
53
+ #
54
+ # %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
55
+ # ["1", "2", "3"]
56
+ # ["4", "5"]
57
+ # ["6", "7"]
58
+ def in_groups(number, fill_with = nil)
59
+ # size / number gives minor group size;
60
+ # size % number gives how many objects need extra accommodation;
61
+ # each group hold either division or division + 1 items.
62
+ division = size / number
63
+ modulo = size % number
64
+
65
+ # create a new array avoiding dup
66
+ groups = []
67
+ start = 0
68
+
69
+ number.times do |index|
70
+ length = division + (modulo > 0 && modulo > index ? 1 : 0)
71
+ padding = fill_with != false &&
72
+ modulo > 0 && length == division ? 1 : 0
73
+ groups << slice(start, length).concat([fill_with] * padding)
74
+ start += length
75
+ end
76
+
77
+ if block_given?
78
+ groups.each { |g| yield(g) }
79
+ else
80
+ groups
81
+ end
82
+ end
83
+
84
+ # Divides the array into one or more subarrays based on a delimiting +value+
85
+ # or the result of an optional block.
86
+ #
87
+ # [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
88
+ # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
89
+ def split(value = nil, &block)
90
+ inject([[]]) do |results, element|
91
+ if block && block.call(element) || value == element
92
+ results << []
93
+ else
94
+ results.last << element
95
+ end
96
+
97
+ results
98
+ end
99
+ end
100
+ end
101
+ end