automate-it 0.9.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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.hgignore +10 -0
- data/.loadpath +5 -0
- data/.project +17 -0
- data/CHANGES.txt +314 -0
- data/Hoe.rake +40 -0
- data/Manifest.txt +164 -0
- data/README.txt +40 -0
- data/Rakefile +256 -0
- data/TESTING.txt +57 -0
- data/TODO.txt +50 -0
- data/TUTORIAL.txt +391 -0
- data/automate-it.gemspec +25 -0
- data/bin/ai +3 -0
- data/bin/aifield +75 -0
- data/bin/aissh +93 -0
- data/bin/aitag +134 -0
- data/bin/automateit +133 -0
- data/docs/friendly_errors.txt +50 -0
- data/docs/previews.txt +86 -0
- data/examples/basic/Rakefile +26 -0
- data/examples/basic/config/automateit_env.rb +16 -0
- data/examples/basic/config/fields.yml +3 -0
- data/examples/basic/config/tags.yml +7 -0
- data/examples/basic/dist/README.txt +9 -0
- data/examples/basic/dist/myapp_server.erb +30 -0
- data/examples/basic/install.log +15 -0
- data/examples/basic/lib/README.txt +10 -0
- data/examples/basic/recipes/README.txt +4 -0
- data/examples/basic/recipes/install.rb +61 -0
- data/examples/basic/recipes/uninstall.rb +6 -0
- data/gpl.txt +674 -0
- data/helpers/cpan_wrapper.pl +220 -0
- data/helpers/which.cmd +7 -0
- data/lib/automateit.rb +55 -0
- data/lib/automateit/account_manager.rb +114 -0
- data/lib/automateit/account_manager/base.rb +138 -0
- data/lib/automateit/account_manager/etc.rb +128 -0
- data/lib/automateit/account_manager/nscd.rb +33 -0
- data/lib/automateit/account_manager/passwd_expect.rb +40 -0
- data/lib/automateit/account_manager/passwd_pty.rb +69 -0
- data/lib/automateit/account_manager/posix.rb +138 -0
- data/lib/automateit/address_manager.rb +88 -0
- data/lib/automateit/address_manager/base.rb +171 -0
- data/lib/automateit/address_manager/bsd.rb +28 -0
- data/lib/automateit/address_manager/freebsd.rb +59 -0
- data/lib/automateit/address_manager/linux.rb +42 -0
- data/lib/automateit/address_manager/openbsd.rb +66 -0
- data/lib/automateit/address_manager/portable.rb +37 -0
- data/lib/automateit/address_manager/sunos.rb +34 -0
- data/lib/automateit/cli.rb +85 -0
- data/lib/automateit/common.rb +65 -0
- data/lib/automateit/constants.rb +35 -0
- data/lib/automateit/download_manager.rb +48 -0
- data/lib/automateit/edit_manager.rb +321 -0
- data/lib/automateit/error.rb +10 -0
- data/lib/automateit/field_manager.rb +103 -0
- data/lib/automateit/interpreter.rb +631 -0
- data/lib/automateit/package_manager.rb +257 -0
- data/lib/automateit/package_manager/apt.rb +27 -0
- data/lib/automateit/package_manager/cpan.rb +101 -0
- data/lib/automateit/package_manager/dpkg.rb +54 -0
- data/lib/automateit/package_manager/egg.rb +64 -0
- data/lib/automateit/package_manager/gem.rb +201 -0
- data/lib/automateit/package_manager/pear.rb +95 -0
- data/lib/automateit/package_manager/pecl.rb +80 -0
- data/lib/automateit/package_manager/portage.rb +69 -0
- data/lib/automateit/package_manager/yum.rb +65 -0
- data/lib/automateit/platform_manager.rb +49 -0
- data/lib/automateit/platform_manager/darwin.rb +30 -0
- data/lib/automateit/platform_manager/debian.rb +26 -0
- data/lib/automateit/platform_manager/freebsd.rb +29 -0
- data/lib/automateit/platform_manager/gentoo.rb +26 -0
- data/lib/automateit/platform_manager/lsb.rb +44 -0
- data/lib/automateit/platform_manager/openbsd.rb +28 -0
- data/lib/automateit/platform_manager/struct.rb +80 -0
- data/lib/automateit/platform_manager/sunos.rb +39 -0
- data/lib/automateit/platform_manager/uname.rb +29 -0
- data/lib/automateit/platform_manager/windows.rb +40 -0
- data/lib/automateit/plugin.rb +7 -0
- data/lib/automateit/plugin/base.rb +32 -0
- data/lib/automateit/plugin/driver.rb +256 -0
- data/lib/automateit/plugin/manager.rb +224 -0
- data/lib/automateit/project.rb +493 -0
- data/lib/automateit/root.rb +17 -0
- data/lib/automateit/service_manager.rb +93 -0
- data/lib/automateit/service_manager/chkconfig.rb +39 -0
- data/lib/automateit/service_manager/rc_update.rb +37 -0
- data/lib/automateit/service_manager/sysv.rb +139 -0
- data/lib/automateit/service_manager/update_rcd.rb +35 -0
- data/lib/automateit/shell_manager.rb +316 -0
- data/lib/automateit/shell_manager/base_link.rb +67 -0
- data/lib/automateit/shell_manager/link.rb +24 -0
- data/lib/automateit/shell_manager/portable.rb +523 -0
- data/lib/automateit/shell_manager/symlink.rb +32 -0
- data/lib/automateit/shell_manager/which_base.rb +30 -0
- data/lib/automateit/shell_manager/which_unix.rb +16 -0
- data/lib/automateit/shell_manager/which_windows.rb +20 -0
- data/lib/automateit/tag_manager.rb +127 -0
- data/lib/automateit/tag_manager/struct.rb +121 -0
- data/lib/automateit/tag_manager/tag_parser.rb +93 -0
- data/lib/automateit/tag_manager/yaml.rb +29 -0
- data/lib/automateit/template_manager.rb +56 -0
- data/lib/automateit/template_manager/base.rb +181 -0
- data/lib/automateit/template_manager/erb.rb +17 -0
- data/lib/ext/metaclass.rb +17 -0
- data/lib/ext/object.rb +18 -0
- data/lib/ext/shell_escape.rb +7 -0
- data/lib/hashcache.rb +22 -0
- data/lib/helpful_erb.rb +63 -0
- data/lib/inactive_support.rb +53 -0
- data/lib/inactive_support/basic_object.rb +6 -0
- data/lib/inactive_support/clean_logger.rb +127 -0
- data/lib/inactive_support/core_ext/array/extract_options.rb +19 -0
- data/lib/inactive_support/core_ext/blank.rb +50 -0
- data/lib/inactive_support/core_ext/class/attribute_accessors.rb +48 -0
- data/lib/inactive_support/core_ext/class/inheritable_attributes.rb +140 -0
- data/lib/inactive_support/core_ext/enumerable.rb +63 -0
- data/lib/inactive_support/core_ext/hash/keys.rb +54 -0
- data/lib/inactive_support/core_ext/module/aliasing.rb +70 -0
- data/lib/inactive_support/core_ext/numeric/time.rb +91 -0
- data/lib/inactive_support/core_ext/string/inflections.rb +153 -0
- data/lib/inactive_support/core_ext/symbol.rb +14 -0
- data/lib/inactive_support/core_ext/time/conversions.rb +96 -0
- data/lib/inactive_support/duration.rb +96 -0
- data/lib/inactive_support/inflections.rb +53 -0
- data/lib/inactive_support/inflector.rb +282 -0
- data/lib/nested_error.rb +33 -0
- data/lib/nitpick.rb +33 -0
- data/lib/queued_logger.rb +68 -0
- data/lib/tempster.rb +250 -0
- data/misc/index_gem_repository.rb +304 -0
- data/misc/setup_egg.rb +12 -0
- data/misc/setup_gem_dependencies.sh +6 -0
- data/misc/setup_rubygems.sh +21 -0
- metadata +279 -0
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'inactive_support/core_ext/class/attribute_accessors'
|
3
|
+
|
4
|
+
# Extensions to the built in Ruby logger.
|
5
|
+
#
|
6
|
+
# If you want to use the default log formatter as defined in the Ruby core, then you
|
7
|
+
# will need to set the formatter for the logger as in:
|
8
|
+
#
|
9
|
+
# logger.formatter = Formatter.new
|
10
|
+
#
|
11
|
+
# You can then specify the datetime format, for example:
|
12
|
+
#
|
13
|
+
# logger.datetime_format = "%Y-%m-%d"
|
14
|
+
#
|
15
|
+
# Note: This logger is deprecated in favor of ActiveSupport::BufferedLogger
|
16
|
+
class Logger
|
17
|
+
# Set to false to disable the silencer
|
18
|
+
cattr_accessor :silencer
|
19
|
+
self.silencer = true
|
20
|
+
|
21
|
+
# Silences the logger for the duration of the block.
|
22
|
+
def silence(temporary_level = Logger::ERROR)
|
23
|
+
if silencer
|
24
|
+
begin
|
25
|
+
old_logger_level, self.level = level, temporary_level
|
26
|
+
yield self
|
27
|
+
ensure
|
28
|
+
self.level = old_logger_level
|
29
|
+
end
|
30
|
+
else
|
31
|
+
yield self
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
alias :old_datetime_format= :datetime_format=
|
36
|
+
# Logging date-time format (string passed to +strftime+). Ignored if the formatter
|
37
|
+
# does not respond to datetime_format=.
|
38
|
+
def datetime_format=(datetime_format)
|
39
|
+
formatter.datetime_format = datetime_format if formatter.respond_to?(:datetime_format=)
|
40
|
+
end
|
41
|
+
|
42
|
+
alias :old_datetime_format :datetime_format
|
43
|
+
# Get the logging datetime format. Returns nil if the formatter does not support
|
44
|
+
# datetime formatting.
|
45
|
+
def datetime_format
|
46
|
+
formatter.datetime_format if formatter.respond_to?(:datetime_format)
|
47
|
+
end
|
48
|
+
|
49
|
+
alias :old_formatter :formatter if method_defined?(:formatter)
|
50
|
+
# Get the current formatter. The default formatter is a SimpleFormatter which only
|
51
|
+
# displays the log message
|
52
|
+
def formatter
|
53
|
+
@formatter ||= SimpleFormatter.new
|
54
|
+
end
|
55
|
+
|
56
|
+
unless const_defined? :Formatter
|
57
|
+
class Formatter
|
58
|
+
Format = "%s, [%s#%d] %5s -- %s: %s\n"
|
59
|
+
|
60
|
+
attr_accessor :datetime_format
|
61
|
+
|
62
|
+
def initialize
|
63
|
+
@datetime_format = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def call(severity, time, progname, msg)
|
67
|
+
Format % [severity[0..0], format_datetime(time), $$, severity, progname,
|
68
|
+
msg2str(msg)]
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
def format_datetime(time)
|
73
|
+
if @datetime_format.nil?
|
74
|
+
time.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d " % time.usec
|
75
|
+
else
|
76
|
+
time.strftime(@datetime_format)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def msg2str(msg)
|
81
|
+
case msg
|
82
|
+
when ::String
|
83
|
+
msg
|
84
|
+
when ::Exception
|
85
|
+
"#{ msg.message } (#{ msg.class })\n" <<
|
86
|
+
(msg.backtrace || []).join("\n")
|
87
|
+
else
|
88
|
+
msg.inspect
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Simple formatter which only displays the message.
|
95
|
+
class SimpleFormatter < Logger::Formatter
|
96
|
+
# This method is invoked when a log event occurs
|
97
|
+
def call(severity, timestamp, progname, msg)
|
98
|
+
"#{String === msg ? msg : msg.inspect}\n"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
alias old_format_message format_message
|
104
|
+
|
105
|
+
# Ruby 1.8.3 transposed the msg and progname arguments to format_message.
|
106
|
+
# We can't test RUBY_VERSION because some distributions don't keep Ruby
|
107
|
+
# and its standard library in sync, leading to installations of Ruby 1.8.2
|
108
|
+
# with Logger from 1.8.3 and vice versa.
|
109
|
+
if method_defined?(:formatter=)
|
110
|
+
def format_message(severity, timestamp, progname, msg)
|
111
|
+
formatter.call(severity, timestamp, progname, msg)
|
112
|
+
end
|
113
|
+
else
|
114
|
+
def format_message(severity, timestamp, msg, progname)
|
115
|
+
formatter.call(severity, timestamp, progname, msg)
|
116
|
+
end
|
117
|
+
|
118
|
+
attr_writer :formatter
|
119
|
+
public :formatter=
|
120
|
+
|
121
|
+
alias old_format_datetime format_datetime
|
122
|
+
def format_datetime(datetime) datetime end
|
123
|
+
|
124
|
+
alias old_msg2str msg2str
|
125
|
+
def msg2str(msg) msg end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module InactiveSupport #:nodoc:
|
2
|
+
module CoreExtensions #:nodoc:
|
3
|
+
module Array #:nodoc:
|
4
|
+
module ExtractOptions
|
5
|
+
# Extract options from a set of arguments. Removes and returns the last element in the array if it's a hash, otherwise returns a blank hash.
|
6
|
+
#
|
7
|
+
# def options(*args)
|
8
|
+
# args.extract_options!
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# options(1, 2) # => {}
|
12
|
+
# options(1, 2, :a => :b) # => {:a=>:b}
|
13
|
+
def extract_options!
|
14
|
+
last.is_a?(::Hash) ? pop : {}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Object
|
2
|
+
# An object is blank if it's nil, empty, or a whitespace string.
|
3
|
+
# For example, "", " ", nil, [], and {} are blank.
|
4
|
+
#
|
5
|
+
# This simplifies
|
6
|
+
# if !address.nil? && !address.empty?
|
7
|
+
# to
|
8
|
+
# if !address.blank?
|
9
|
+
def blank?
|
10
|
+
respond_to?(:empty?) ? empty? : !self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class NilClass #:nodoc:
|
15
|
+
def blank?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class FalseClass #:nodoc:
|
21
|
+
def blank?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class TrueClass #:nodoc:
|
27
|
+
def blank?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Array #:nodoc:
|
33
|
+
alias_method :blank?, :empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
class Hash #:nodoc:
|
37
|
+
alias_method :blank?, :empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
class String #:nodoc:
|
41
|
+
def blank?
|
42
|
+
self !~ /\S/
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Numeric #:nodoc:
|
47
|
+
def blank?
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Extends the class object with class and instance accessors for class attributes,
|
2
|
+
# just like the native attr* accessors for instance attributes.
|
3
|
+
class Class # :nodoc:
|
4
|
+
def cattr_reader(*syms)
|
5
|
+
syms.flatten.each do |sym|
|
6
|
+
next if sym.is_a?(Hash)
|
7
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
8
|
+
unless defined? @@#{sym}
|
9
|
+
@@#{sym} = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.#{sym}
|
13
|
+
@@#{sym}
|
14
|
+
end
|
15
|
+
|
16
|
+
def #{sym}
|
17
|
+
@@#{sym}
|
18
|
+
end
|
19
|
+
EOS
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def cattr_writer(*syms)
|
24
|
+
options = syms.extract_options!
|
25
|
+
syms.flatten.each do |sym|
|
26
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
27
|
+
unless defined? @@#{sym}
|
28
|
+
@@#{sym} = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.#{sym}=(obj)
|
32
|
+
@@#{sym} = obj
|
33
|
+
end
|
34
|
+
|
35
|
+
#{"
|
36
|
+
def #{sym}=(obj)
|
37
|
+
@@#{sym} = obj
|
38
|
+
end
|
39
|
+
" unless options[:instance_writer] == false }
|
40
|
+
EOS
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def cattr_accessor(*syms)
|
45
|
+
cattr_reader(*syms)
|
46
|
+
cattr_writer(*syms)
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# Retain for backward compatibility. Methods are now included in Class.
|
2
|
+
module ClassInheritableAttributes # :nodoc:
|
3
|
+
end
|
4
|
+
|
5
|
+
# Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
|
6
|
+
# their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
|
7
|
+
# to, for example, an array without those additions being shared with either their parent, siblings, or
|
8
|
+
# children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
|
9
|
+
class Class # :nodoc:
|
10
|
+
def class_inheritable_reader(*syms)
|
11
|
+
syms.each do |sym|
|
12
|
+
next if sym.is_a?(Hash)
|
13
|
+
class_eval <<-EOS
|
14
|
+
def self.#{sym}
|
15
|
+
read_inheritable_attribute(:#{sym})
|
16
|
+
end
|
17
|
+
|
18
|
+
def #{sym}
|
19
|
+
self.class.#{sym}
|
20
|
+
end
|
21
|
+
EOS
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def class_inheritable_writer(*syms)
|
26
|
+
options = syms.extract_options!
|
27
|
+
syms.each do |sym|
|
28
|
+
class_eval <<-EOS
|
29
|
+
def self.#{sym}=(obj)
|
30
|
+
write_inheritable_attribute(:#{sym}, obj)
|
31
|
+
end
|
32
|
+
|
33
|
+
#{"
|
34
|
+
def #{sym}=(obj)
|
35
|
+
self.class.#{sym} = obj
|
36
|
+
end
|
37
|
+
" unless options[:instance_writer] == false }
|
38
|
+
EOS
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def class_inheritable_array_writer(*syms)
|
43
|
+
options = syms.extract_options!
|
44
|
+
syms.each do |sym|
|
45
|
+
class_eval <<-EOS
|
46
|
+
def self.#{sym}=(obj)
|
47
|
+
write_inheritable_array(:#{sym}, obj)
|
48
|
+
end
|
49
|
+
|
50
|
+
#{"
|
51
|
+
def #{sym}=(obj)
|
52
|
+
self.class.#{sym} = obj
|
53
|
+
end
|
54
|
+
" unless options[:instance_writer] == false }
|
55
|
+
EOS
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def class_inheritable_hash_writer(*syms)
|
60
|
+
options = syms.extract_options!
|
61
|
+
syms.each do |sym|
|
62
|
+
class_eval <<-EOS
|
63
|
+
def self.#{sym}=(obj)
|
64
|
+
write_inheritable_hash(:#{sym}, obj)
|
65
|
+
end
|
66
|
+
|
67
|
+
#{"
|
68
|
+
def #{sym}=(obj)
|
69
|
+
self.class.#{sym} = obj
|
70
|
+
end
|
71
|
+
" unless options[:instance_writer] == false }
|
72
|
+
EOS
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def class_inheritable_accessor(*syms)
|
77
|
+
class_inheritable_reader(*syms)
|
78
|
+
class_inheritable_writer(*syms)
|
79
|
+
end
|
80
|
+
|
81
|
+
def class_inheritable_array(*syms)
|
82
|
+
class_inheritable_reader(*syms)
|
83
|
+
class_inheritable_array_writer(*syms)
|
84
|
+
end
|
85
|
+
|
86
|
+
def class_inheritable_hash(*syms)
|
87
|
+
class_inheritable_reader(*syms)
|
88
|
+
class_inheritable_hash_writer(*syms)
|
89
|
+
end
|
90
|
+
|
91
|
+
def inheritable_attributes
|
92
|
+
@inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
|
93
|
+
end
|
94
|
+
|
95
|
+
def write_inheritable_attribute(key, value)
|
96
|
+
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
|
97
|
+
@inheritable_attributes = {}
|
98
|
+
end
|
99
|
+
inheritable_attributes[key] = value
|
100
|
+
end
|
101
|
+
|
102
|
+
def write_inheritable_array(key, elements)
|
103
|
+
write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
|
104
|
+
write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
|
105
|
+
end
|
106
|
+
|
107
|
+
def write_inheritable_hash(key, hash)
|
108
|
+
write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
|
109
|
+
write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
|
110
|
+
end
|
111
|
+
|
112
|
+
def read_inheritable_attribute(key)
|
113
|
+
inheritable_attributes[key]
|
114
|
+
end
|
115
|
+
|
116
|
+
def reset_inheritable_attributes
|
117
|
+
@inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
# Prevent this constant from being created multiple times
|
122
|
+
EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze unless const_defined?(:EMPTY_INHERITABLE_ATTRIBUTES)
|
123
|
+
|
124
|
+
def inherited_with_inheritable_attributes(child)
|
125
|
+
inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
|
126
|
+
|
127
|
+
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
|
128
|
+
new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
|
129
|
+
else
|
130
|
+
new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
|
131
|
+
memo.update(key => (value.dup rescue value))
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
|
136
|
+
end
|
137
|
+
|
138
|
+
alias inherited_without_inheritable_attributes inherited
|
139
|
+
alias inherited inherited_with_inheritable_attributes
|
140
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Enumerable
|
2
|
+
# Collect an enumerable into sets, grouped by the result of a block. Useful,
|
3
|
+
# for example, for grouping records by date.
|
4
|
+
#
|
5
|
+
# e.g.
|
6
|
+
#
|
7
|
+
# latest_transcripts.group_by(&:day).each do |day, transcripts|
|
8
|
+
# p "#{day} -> #{transcripts.map(&:class) * ', '}"
|
9
|
+
# end
|
10
|
+
# "2006-03-01 -> Transcript"
|
11
|
+
# "2006-02-28 -> Transcript"
|
12
|
+
# "2006-02-27 -> Transcript, Transcript"
|
13
|
+
# "2006-02-26 -> Transcript, Transcript"
|
14
|
+
# "2006-02-25 -> Transcript"
|
15
|
+
# "2006-02-24 -> Transcript, Transcript"
|
16
|
+
# "2006-02-23 -> Transcript"
|
17
|
+
def group_by
|
18
|
+
inject({}) do |groups, element|
|
19
|
+
(groups[yield(element)] ||= []) << element
|
20
|
+
groups
|
21
|
+
end
|
22
|
+
end if RUBY_VERSION < '1.9'
|
23
|
+
|
24
|
+
# Calculates a sum from the elements. Examples:
|
25
|
+
#
|
26
|
+
# payments.sum { |p| p.price * p.tax_rate }
|
27
|
+
# payments.sum(&:price)
|
28
|
+
#
|
29
|
+
# This is instead of payments.inject { |sum, p| sum + p.price }
|
30
|
+
#
|
31
|
+
# Also calculates sums without the use of a block:
|
32
|
+
# [5, 15, 10].sum # => 30
|
33
|
+
#
|
34
|
+
# The default identity (sum of an empty list) is zero.
|
35
|
+
# However, you can override this default:
|
36
|
+
#
|
37
|
+
# [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
|
38
|
+
#
|
39
|
+
def sum(identity = 0, &block)
|
40
|
+
return identity unless size > 0
|
41
|
+
|
42
|
+
if block_given?
|
43
|
+
map(&block).sum
|
44
|
+
else
|
45
|
+
inject { |sum, element| sum + element }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Convert an enumerable to a hash. Examples:
|
50
|
+
#
|
51
|
+
# people.index_by(&:login)
|
52
|
+
# => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
|
53
|
+
# people.index_by { |person| "#{person.first_name} #{person.last_name}" }
|
54
|
+
# => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
|
55
|
+
#
|
56
|
+
def index_by
|
57
|
+
inject({}) do |accum, elem|
|
58
|
+
accum[yield(elem)] = elem
|
59
|
+
accum
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|