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.
- data/.gitignore +17 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +32 -0
- data/Rakefile +1 -0
- data/activesupport-refinements.gemspec +21 -0
- data/lib/active_support/refinements/core_ext/array.rb +7 -0
- data/lib/active_support/refinements/core_ext/array/access.rb +56 -0
- data/lib/active_support/refinements/core_ext/array/conversions.rb +224 -0
- data/lib/active_support/refinements/core_ext/array/extract_options.rb +31 -0
- data/lib/active_support/refinements/core_ext/array/grouping.rb +101 -0
- data/lib/active_support/refinements/core_ext/array/prepend_and_append.rb +9 -0
- data/lib/active_support/refinements/core_ext/array/uniq_by.rb +21 -0
- data/lib/active_support/refinements/core_ext/array/wrap.rb +48 -0
- data/lib/active_support/refinements/core_ext/benchmark.rb +7 -0
- data/lib/active_support/refinements/core_ext/big_decimal.rb +1 -0
- data/lib/active_support/refinements/core_ext/big_decimal/conversions.rb +32 -0
- data/lib/active_support/refinements/core_ext/class.rb +4 -0
- data/lib/active_support/refinements/core_ext/class/attribute.rb +119 -0
- data/lib/active_support/refinements/core_ext/class/attribute_accessors.rb +172 -0
- data/lib/active_support/refinements/core_ext/class/delegating_attributes.rb +42 -0
- data/lib/active_support/refinements/core_ext/class/subclasses.rb +44 -0
- data/lib/active_support/refinements/core_ext/date.rb +5 -0
- data/lib/active_support/refinements/core_ext/date/acts_like.rb +10 -0
- data/lib/active_support/refinements/core_ext/date/calculations.rb +123 -0
- data/lib/active_support/refinements/core_ext/date/conversions.rb +86 -0
- data/lib/active_support/refinements/core_ext/date/zones.rb +17 -0
- data/lib/active_support/refinements/core_ext/date_and_time/calculations.rb +232 -0
- data/lib/active_support/refinements/core_ext/date_time.rb +4 -0
- data/lib/active_support/refinements/core_ext/date_time/acts_like.rb +15 -0
- data/lib/active_support/refinements/core_ext/date_time/calculations.rb +143 -0
- data/lib/active_support/refinements/core_ext/date_time/conversions.rb +93 -0
- data/lib/active_support/refinements/core_ext/date_time/zones.rb +26 -0
- data/lib/active_support/refinements/core_ext/enumerable.rb +82 -0
- data/lib/active_support/refinements/core_ext/exception.rb +5 -0
- data/lib/active_support/refinements/core_ext/file.rb +1 -0
- data/lib/active_support/refinements/core_ext/file/atomic.rb +60 -0
- data/lib/active_support/refinements/core_ext/hash.rb +8 -0
- data/lib/active_support/refinements/core_ext/hash/conversions.rb +161 -0
- data/lib/active_support/refinements/core_ext/hash/deep_merge.rb +29 -0
- data/lib/active_support/refinements/core_ext/hash/diff.rb +15 -0
- data/lib/active_support/refinements/core_ext/hash/except.rb +17 -0
- data/lib/active_support/refinements/core_ext/hash/indifferent_access.rb +24 -0
- data/lib/active_support/refinements/core_ext/hash/keys.rb +140 -0
- data/lib/active_support/refinements/core_ext/hash/reverse_merge.rb +24 -0
- data/lib/active_support/refinements/core_ext/hash/slice.rb +42 -0
- data/lib/active_support/refinements/core_ext/integer.rb +3 -0
- data/lib/active_support/refinements/core_ext/integer/inflections.rb +31 -0
- data/lib/active_support/refinements/core_ext/integer/multiple.rb +12 -0
- data/lib/active_support/refinements/core_ext/integer/time.rb +43 -0
- data/lib/active_support/refinements/core_ext/kernel.rb +4 -0
- data/lib/active_support/refinements/core_ext/kernel/agnostics.rb +13 -0
- data/lib/active_support/refinements/core_ext/kernel/debugger.rb +12 -0
- data/lib/active_support/refinements/core_ext/kernel/reporting.rb +97 -0
- data/lib/active_support/refinements/core_ext/kernel/singleton_class.rb +8 -0
- data/lib/active_support/refinements/core_ext/load_error.rb +27 -0
- data/lib/active_support/refinements/core_ext/logger.rb +86 -0
- data/lib/active_support/refinements/core_ext/module.rb +10 -0
- data/lib/active_support/refinements/core_ext/module/aliasing.rb +69 -0
- data/lib/active_support/refinements/core_ext/module/anonymous.rb +21 -0
- data/lib/active_support/refinements/core_ext/module/attr_internal.rb +40 -0
- data/lib/active_support/refinements/core_ext/module/attribute_accessors.rb +68 -0
- data/lib/active_support/refinements/core_ext/module/delegation.rb +172 -0
- data/lib/active_support/refinements/core_ext/module/deprecation.rb +27 -0
- data/lib/active_support/refinements/core_ext/module/introspection.rb +80 -0
- data/lib/active_support/refinements/core_ext/module/qualified_const.rb +54 -0
- data/lib/active_support/refinements/core_ext/module/reachable.rb +10 -0
- data/lib/active_support/refinements/core_ext/module/remove_method.rb +14 -0
- data/lib/active_support/refinements/core_ext/name_error.rb +20 -0
- data/lib/active_support/refinements/core_ext/numeric.rb +3 -0
- data/lib/active_support/refinements/core_ext/numeric/bytes.rb +46 -0
- data/lib/active_support/refinements/core_ext/numeric/conversions.rb +137 -0
- data/lib/active_support/refinements/core_ext/numeric/time.rb +81 -0
- data/lib/active_support/refinements/core_ext/object.rb +14 -0
- data/lib/active_support/refinements/core_ext/object/acts_like.rb +12 -0
- data/lib/active_support/refinements/core_ext/object/blank.rb +107 -0
- data/lib/active_support/refinements/core_ext/object/conversions.rb +4 -0
- data/lib/active_support/refinements/core_ext/object/deep_dup.rb +48 -0
- data/lib/active_support/refinements/core_ext/object/duplicable.rb +92 -0
- data/lib/active_support/refinements/core_ext/object/inclusion.rb +27 -0
- data/lib/active_support/refinements/core_ext/object/instance_variables.rb +30 -0
- data/lib/active_support/refinements/core_ext/object/to_json.rb +27 -0
- data/lib/active_support/refinements/core_ext/object/to_param.rb +60 -0
- data/lib/active_support/refinements/core_ext/object/to_query.rb +29 -0
- data/lib/active_support/refinements/core_ext/object/try.rb +72 -0
- data/lib/active_support/refinements/core_ext/object/with_options.rb +44 -0
- data/lib/active_support/refinements/core_ext/proc.rb +19 -0
- data/lib/active_support/refinements/core_ext/range.rb +3 -0
- data/lib/active_support/refinements/core_ext/range/conversions.rb +21 -0
- data/lib/active_support/refinements/core_ext/range/include_range.rb +23 -0
- data/lib/active_support/refinements/core_ext/range/overlaps.rb +10 -0
- data/lib/active_support/refinements/core_ext/regexp.rb +7 -0
- data/lib/active_support/refinements/core_ext/string.rb +13 -0
- data/lib/active_support/refinements/core_ext/string/access.rb +106 -0
- data/lib/active_support/refinements/core_ext/string/behavior.rb +8 -0
- data/lib/active_support/refinements/core_ext/string/conversions.rb +60 -0
- data/lib/active_support/refinements/core_ext/string/encoding.rb +10 -0
- data/lib/active_support/refinements/core_ext/string/exclude.rb +13 -0
- data/lib/active_support/refinements/core_ext/string/filters.rb +54 -0
- data/lib/active_support/refinements/core_ext/string/indent.rb +45 -0
- data/lib/active_support/refinements/core_ext/string/inflections.rb +214 -0
- data/lib/active_support/refinements/core_ext/string/inquiry.rb +15 -0
- data/lib/active_support/refinements/core_ext/string/multibyte.rb +58 -0
- data/lib/active_support/refinements/core_ext/string/output_safety.rb +194 -0
- data/lib/active_support/refinements/core_ext/string/starts_ends_with.rb +6 -0
- data/lib/active_support/refinements/core_ext/string/strip.rb +28 -0
- data/lib/active_support/refinements/core_ext/string/xchar.rb +18 -0
- data/lib/active_support/refinements/core_ext/time.rb +5 -0
- data/lib/active_support/refinements/core_ext/time/acts_like.rb +10 -0
- data/lib/active_support/refinements/core_ext/time/calculations.rb +251 -0
- data/lib/active_support/refinements/core_ext/time/conversions.rb +65 -0
- data/lib/active_support/refinements/core_ext/time/marshal.rb +30 -0
- data/lib/active_support/refinements/core_ext/time/zones.rb +98 -0
- data/lib/active_support/refinements/core_ext/uri.rb +28 -0
- data/lib/activesupport-refinements.rb +9 -0
- data/lib/activesupport-refinements/version.rb +5 -0
- data/refine_core_ext.rb +45 -0
- data/spec/hwia_spec.rb +15 -0
- data/spec/try_spec.rb +18 -0
- metadata +182 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -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.
|
data/README.md
ADDED
|
@@ -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
|
data/Rakefile
ADDED
|
@@ -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, ' ') {|group| p group}
|
|
13
|
+
# ["1", "2"]
|
|
14
|
+
# ["3", "4"]
|
|
15
|
+
# ["5", " "]
|
|
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, ' ') {|group| p group}
|
|
50
|
+
# ["1", "2", "3", "4"]
|
|
51
|
+
# ["5", "6", "7", " "]
|
|
52
|
+
# ["8", "9", "10", " "]
|
|
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
|