sigterm_extensions 0.0.4
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/CHANGELOG.md +17 -0
- data/Gemfile +6 -0
- data/LICENSE.md +0 -0
- data/README.md +0 -0
- data/bin/ctxirb +156 -0
- data/lib/git.rb +166 -0
- data/lib/git/LICENSE +21 -0
- data/lib/git/author.rb +14 -0
- data/lib/git/base.rb +551 -0
- data/lib/git/base/factory.rb +75 -0
- data/lib/git/branch.rb +126 -0
- data/lib/git/branches.rb +71 -0
- data/lib/git/config.rb +22 -0
- data/lib/git/diff.rb +159 -0
- data/lib/git/index.rb +5 -0
- data/lib/git/lib.rb +1041 -0
- data/lib/git/log.rb +128 -0
- data/lib/git/object.rb +312 -0
- data/lib/git/path.rb +31 -0
- data/lib/git/remote.rb +36 -0
- data/lib/git/repository.rb +6 -0
- data/lib/git/stash.rb +27 -0
- data/lib/git/stashes.rb +55 -0
- data/lib/git/status.rb +199 -0
- data/lib/git/version.rb +5 -0
- data/lib/git/working_directory.rb +4 -0
- data/lib/sigterm_extensions.rb +75 -0
- data/lib/sigterm_extensions/all.rb +12 -0
- data/lib/sigterm_extensions/backtrace_cleaner.rb +129 -0
- data/lib/sigterm_extensions/callbacks.rb +847 -0
- data/lib/sigterm_extensions/concern.rb +169 -0
- data/lib/sigterm_extensions/configurable.rb +38 -0
- data/lib/sigterm_extensions/core_ext.rb +4 -0
- data/lib/sigterm_extensions/core_ext/array.rb +3 -0
- data/lib/sigterm_extensions/core_ext/array/extract.rb +19 -0
- data/lib/sigterm_extensions/core_ext/array/extract_options.rb +29 -0
- data/lib/sigterm_extensions/core_ext/class.rb +3 -0
- data/lib/sigterm_extensions/core_ext/class/attribute.rb +139 -0
- data/lib/sigterm_extensions/core_ext/class/attribute_accessors.rb +4 -0
- data/lib/sigterm_extensions/core_ext/class/subclasses.rb +52 -0
- data/lib/sigterm_extensions/core_ext/custom.rb +12 -0
- data/lib/sigterm_extensions/core_ext/digest.rb +3 -0
- data/lib/sigterm_extensions/core_ext/digest/uuid.rb +51 -0
- data/lib/sigterm_extensions/core_ext/enumerable.rb +232 -0
- data/lib/sigterm_extensions/core_ext/file.rb +3 -0
- data/lib/sigterm_extensions/core_ext/file/atomic.rb +68 -0
- data/lib/sigterm_extensions/core_ext/hash.rb +3 -0
- data/lib/sigterm_extensions/core_ext/hash/deep_merge.rb +41 -0
- data/lib/sigterm_extensions/core_ext/hash/deep_transform_values.rb +44 -0
- data/lib/sigterm_extensions/core_ext/hash/except.rb +22 -0
- data/lib/sigterm_extensions/core_ext/hash/keys.rb +141 -0
- data/lib/sigterm_extensions/core_ext/hash/reverse_merge.rb +23 -0
- data/lib/sigterm_extensions/core_ext/hash/slice.rb +24 -0
- data/lib/sigterm_extensions/core_ext/kernel.rb +3 -0
- data/lib/sigterm_extensions/core_ext/kernel/concern.rb +12 -0
- data/lib/sigterm_extensions/core_ext/kernel/reporting.rb +43 -0
- data/lib/sigterm_extensions/core_ext/kernel/singleton_class.rb +6 -0
- data/lib/sigterm_extensions/core_ext/load_error.rb +7 -0
- data/lib/sigterm_extensions/core_ext/module.rb +3 -0
- data/lib/sigterm_extensions/core_ext/module/aliasing.rb +29 -0
- data/lib/sigterm_extensions/core_ext/module/anonymous.rb +28 -0
- data/lib/sigterm_extensions/core_ext/module/attr_internal.rb +36 -0
- data/lib/sigterm_extensions/core_ext/module/attribute_accessors.rb +208 -0
- data/lib/sigterm_extensions/core_ext/module/attribute_accessors_per_thread.rb +146 -0
- data/lib/sigterm_extensions/core_ext/module/concerning.rb +132 -0
- data/lib/sigterm_extensions/core_ext/module/delegation.rb +319 -0
- data/lib/sigterm_extensions/core_ext/module/redefine_method.rb +38 -0
- data/lib/sigterm_extensions/core_ext/module/remove_method.rb +15 -0
- data/lib/sigterm_extensions/core_ext/name_error.rb +36 -0
- data/lib/sigterm_extensions/core_ext/object.rb +3 -0
- data/lib/sigterm_extensions/core_ext/object/blank.rb +153 -0
- data/lib/sigterm_extensions/core_ext/object/colors.rb +39 -0
- data/lib/sigterm_extensions/core_ext/object/duplicable.rb +47 -0
- data/lib/sigterm_extensions/core_ext/object/inclusion.rb +27 -0
- data/lib/sigterm_extensions/core_ext/object/instance_variables.rb +28 -0
- data/lib/sigterm_extensions/core_ext/object/methods.rb +61 -0
- data/lib/sigterm_extensions/core_ext/object/with_options.rb +80 -0
- data/lib/sigterm_extensions/core_ext/range.rb +3 -0
- data/lib/sigterm_extensions/core_ext/range/compare_range.rb +74 -0
- data/lib/sigterm_extensions/core_ext/range/conversions.rb +39 -0
- data/lib/sigterm_extensions/core_ext/range/overlaps.rb +8 -0
- data/lib/sigterm_extensions/core_ext/securerandom.rb +43 -0
- data/lib/sigterm_extensions/core_ext/string.rb +3 -0
- data/lib/sigterm_extensions/core_ext/string/access.rb +93 -0
- data/lib/sigterm_extensions/core_ext/string/filters.rb +143 -0
- data/lib/sigterm_extensions/core_ext/string/starts_ends_with.rb +4 -0
- data/lib/sigterm_extensions/core_ext/string/strip.rb +25 -0
- data/lib/sigterm_extensions/core_ext/tryable.rb +132 -0
- data/lib/sigterm_extensions/descendants_tracker.rb +108 -0
- data/lib/sigterm_extensions/gem_methods.rb +47 -0
- data/lib/sigterm_extensions/hash_binding.rb +16 -0
- data/lib/sigterm_extensions/inflector.rb +339 -0
- data/lib/sigterm_extensions/inflector/acronyms.rb +42 -0
- data/lib/sigterm_extensions/inflector/inflections.rb +249 -0
- data/lib/sigterm_extensions/inflector/inflections/defaults.rb +117 -0
- data/lib/sigterm_extensions/inflector/rules.rb +37 -0
- data/lib/sigterm_extensions/inflector/version.rb +8 -0
- data/lib/sigterm_extensions/interactive_editor.rb +120 -0
- data/lib/sigterm_extensions/lazy.rb +34 -0
- data/lib/sigterm_extensions/lazy_load_hooks.rb +79 -0
- data/lib/sigterm_extensions/option_merger.rb +32 -0
- data/lib/sigterm_extensions/ordered_hash.rb +48 -0
- data/lib/sigterm_extensions/ordered_options.rb +83 -0
- data/lib/sigterm_extensions/paths.rb +235 -0
- data/lib/sigterm_extensions/per_thread_registry.rb +58 -0
- data/lib/sigterm_extensions/proxy_object.rb +14 -0
- data/lib/sigterm_extensions/staging/boot.rb +31 -0
- data/lib/sigterm_extensions/staging/boot/bundler_patch.rb +24 -0
- data/lib/sigterm_extensions/staging/boot/command.rb +26 -0
- data/lib/sigterm_extensions/staging/boot/gemfile_next_auto_sync.rb +79 -0
- data/lib/sigterm_extensions/version.rb +4 -0
- data/lib/sigterm_extensions/wrappable.rb +16 -0
- data/sigterm_extensions.gemspec +42 -0
- data/templates/dotpryrc.rb.erb +124 -0
- metadata +315 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class Hash
|
|
2
|
+
# Returns a hash that includes everything except given keys.
|
|
3
|
+
# hash = { a: true, b: false, c: nil }
|
|
4
|
+
# hash.except(:c) # => { a: true, b: false }
|
|
5
|
+
# hash.except(:a, :b) # => { c: nil }
|
|
6
|
+
# hash # => { a: true, b: false, c: nil }
|
|
7
|
+
#
|
|
8
|
+
# This is useful for limiting a set of parameters to everything but a few known toggles:
|
|
9
|
+
# @person.update(params[:person].except(:admin))
|
|
10
|
+
def except(*keys)
|
|
11
|
+
slice(*self.keys - keys)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Removes the given keys from hash and returns it.
|
|
15
|
+
# hash = { a: true, b: false, c: nil }
|
|
16
|
+
# hash.except!(:c) # => { a: true, b: false }
|
|
17
|
+
# hash # => { a: true, b: false }
|
|
18
|
+
def except!(*keys)
|
|
19
|
+
keys.each { |key| delete(key) }
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
class Hash
|
|
2
|
+
# Returns a new hash with all keys converted to strings.
|
|
3
|
+
#
|
|
4
|
+
# hash = { name: 'Rob', age: '28' }
|
|
5
|
+
#
|
|
6
|
+
# hash.stringify_keys
|
|
7
|
+
# # => {"name"=>"Rob", "age"=>"28"}
|
|
8
|
+
def stringify_keys
|
|
9
|
+
transform_keys(&:to_s)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Destructively converts all keys to strings. Same as
|
|
13
|
+
# +stringify_keys+, but modifies +self+.
|
|
14
|
+
def stringify_keys!
|
|
15
|
+
transform_keys!(&:to_s)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Returns a new hash with all keys converted to symbols, as long as
|
|
19
|
+
# they respond to +to_sym+.
|
|
20
|
+
#
|
|
21
|
+
# hash = { 'name' => 'Rob', 'age' => '28' }
|
|
22
|
+
#
|
|
23
|
+
# hash.symbolize_keys
|
|
24
|
+
# # => {:name=>"Rob", :age=>"28"}
|
|
25
|
+
def symbolize_keys
|
|
26
|
+
transform_keys { |key| key.to_sym rescue key }
|
|
27
|
+
end
|
|
28
|
+
alias_method :to_options, :symbolize_keys
|
|
29
|
+
|
|
30
|
+
# Destructively converts all keys to symbols, as long as they respond
|
|
31
|
+
# to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
|
|
32
|
+
def symbolize_keys!
|
|
33
|
+
transform_keys! { |key| key.to_sym rescue key }
|
|
34
|
+
end
|
|
35
|
+
alias_method :to_options!, :symbolize_keys!
|
|
36
|
+
|
|
37
|
+
# Validates all keys in a hash match <tt>*valid_keys</tt>, raising
|
|
38
|
+
# +ArgumentError+ on a mismatch.
|
|
39
|
+
#
|
|
40
|
+
# Note that keys are treated differently than HashWithIndifferentAccess,
|
|
41
|
+
# meaning that string and symbol keys will not match.
|
|
42
|
+
#
|
|
43
|
+
# { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: :years. Valid keys are: :name, :age"
|
|
44
|
+
# { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: :name. Valid keys are: 'name', 'age'"
|
|
45
|
+
# { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
|
|
46
|
+
def assert_valid_keys(*valid_keys)
|
|
47
|
+
valid_keys.flatten!
|
|
48
|
+
each_key do |k|
|
|
49
|
+
unless valid_keys.include?(k)
|
|
50
|
+
raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Returns a new hash with all keys converted by the block operation.
|
|
56
|
+
# This includes the keys from the root hash and from all
|
|
57
|
+
# nested hashes and arrays.
|
|
58
|
+
#
|
|
59
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
|
60
|
+
#
|
|
61
|
+
# hash.deep_transform_keys{ |key| key.to_s.upcase }
|
|
62
|
+
# # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
|
|
63
|
+
def deep_transform_keys(&block)
|
|
64
|
+
_deep_transform_keys_in_object(self, &block)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Destructively converts all keys by using the block operation.
|
|
68
|
+
# This includes the keys from the root hash and from all
|
|
69
|
+
# nested hashes and arrays.
|
|
70
|
+
def deep_transform_keys!(&block)
|
|
71
|
+
_deep_transform_keys_in_object!(self, &block)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Returns a new hash with all keys converted to strings.
|
|
75
|
+
# This includes the keys from the root hash and from all
|
|
76
|
+
# nested hashes and arrays.
|
|
77
|
+
#
|
|
78
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
|
79
|
+
#
|
|
80
|
+
# hash.deep_stringify_keys
|
|
81
|
+
# # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
|
|
82
|
+
def deep_stringify_keys
|
|
83
|
+
deep_transform_keys(&:to_s)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Destructively converts all keys to strings.
|
|
87
|
+
# This includes the keys from the root hash and from all
|
|
88
|
+
# nested hashes and arrays.
|
|
89
|
+
def deep_stringify_keys!
|
|
90
|
+
deep_transform_keys!(&:to_s)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Returns a new hash with all keys converted to symbols, as long as
|
|
94
|
+
# they respond to +to_sym+. This includes the keys from the root hash
|
|
95
|
+
# and from all nested hashes and arrays.
|
|
96
|
+
#
|
|
97
|
+
# hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
|
|
98
|
+
#
|
|
99
|
+
# hash.deep_symbolize_keys
|
|
100
|
+
# # => {:person=>{:name=>"Rob", :age=>"28"}}
|
|
101
|
+
def deep_symbolize_keys
|
|
102
|
+
deep_transform_keys { |key| key.to_sym rescue key }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Destructively converts all keys to symbols, as long as they respond
|
|
106
|
+
# to +to_sym+. This includes the keys from the root hash and from all
|
|
107
|
+
# nested hashes and arrays.
|
|
108
|
+
def deep_symbolize_keys!
|
|
109
|
+
deep_transform_keys! { |key| key.to_sym rescue key }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
# support methods for deep transforming nested hashes and arrays
|
|
114
|
+
def _deep_transform_keys_in_object(object, &block)
|
|
115
|
+
case object
|
|
116
|
+
when Hash
|
|
117
|
+
object.each_with_object({}) do |(key, value), result|
|
|
118
|
+
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
|
|
119
|
+
end
|
|
120
|
+
when Array
|
|
121
|
+
object.map { |e| _deep_transform_keys_in_object(e, &block) }
|
|
122
|
+
else
|
|
123
|
+
object
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def _deep_transform_keys_in_object!(object, &block)
|
|
128
|
+
case object
|
|
129
|
+
when Hash
|
|
130
|
+
object.keys.each do |key|
|
|
131
|
+
value = object.delete(key)
|
|
132
|
+
object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
|
|
133
|
+
end
|
|
134
|
+
object
|
|
135
|
+
when Array
|
|
136
|
+
object.map! { |e| _deep_transform_keys_in_object!(e, &block) }
|
|
137
|
+
else
|
|
138
|
+
object
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class Hash
|
|
2
|
+
# Merges the caller into +other_hash+. For example,
|
|
3
|
+
#
|
|
4
|
+
# options = options.reverse_merge(size: 25, velocity: 10)
|
|
5
|
+
#
|
|
6
|
+
# is equivalent to
|
|
7
|
+
#
|
|
8
|
+
# options = { size: 25, velocity: 10 }.merge(options)
|
|
9
|
+
#
|
|
10
|
+
# This is particularly useful for initializing an options hash
|
|
11
|
+
# with default values.
|
|
12
|
+
def reverse_merge(other_hash)
|
|
13
|
+
other_hash.merge(self)
|
|
14
|
+
end
|
|
15
|
+
alias_method :with_defaults, :reverse_merge
|
|
16
|
+
|
|
17
|
+
# Destructive +reverse_merge+.
|
|
18
|
+
def reverse_merge!(other_hash)
|
|
19
|
+
replace(reverse_merge(other_hash))
|
|
20
|
+
end
|
|
21
|
+
alias_method :reverse_update, :reverse_merge!
|
|
22
|
+
alias_method :with_defaults!, :reverse_merge!
|
|
23
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class Hash
|
|
2
|
+
# Replaces the hash with only the given keys.
|
|
3
|
+
# Returns a hash containing the removed key/value pairs.
|
|
4
|
+
#
|
|
5
|
+
# hash = { a: 1, b: 2, c: 3, d: 4 }
|
|
6
|
+
# hash.slice!(:a, :b) # => {:c=>3, :d=>4}
|
|
7
|
+
# hash # => {:a=>1, :b=>2}
|
|
8
|
+
def slice!(*keys)
|
|
9
|
+
omit = slice(*self.keys - keys)
|
|
10
|
+
hash = slice(*keys)
|
|
11
|
+
hash.default = default
|
|
12
|
+
hash.default_proc = default_proc if default_proc
|
|
13
|
+
replace(hash)
|
|
14
|
+
omit
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Removes and returns the key/value pairs matching the given keys.
|
|
18
|
+
#
|
|
19
|
+
# { a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b) # => {:a=>1, :b=>2}
|
|
20
|
+
# { a: 1, b: 2 }.extract!(:a, :x) # => {:a=>1}
|
|
21
|
+
def extract!(*keys)
|
|
22
|
+
keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require "sigterm_extensions/core_ext/module/concerning"
|
|
2
|
+
|
|
3
|
+
module Kernel
|
|
4
|
+
module_function
|
|
5
|
+
|
|
6
|
+
# A shortcut to define a toplevel concern, not within a module.
|
|
7
|
+
#
|
|
8
|
+
# See Module::Concerning for more.
|
|
9
|
+
def concern(topic, &module_definition)
|
|
10
|
+
Object.concern topic, &module_definition
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Kernel
|
|
2
|
+
module_function
|
|
3
|
+
|
|
4
|
+
# Sets $VERBOSE to +nil+ for the duration of the block and back to its original
|
|
5
|
+
# value afterwards.
|
|
6
|
+
#
|
|
7
|
+
# silence_warnings do
|
|
8
|
+
# value = noisy_call # no warning voiced
|
|
9
|
+
# end
|
|
10
|
+
#
|
|
11
|
+
# noisy_call # warning voiced
|
|
12
|
+
def silence_warnings
|
|
13
|
+
with_warnings(nil) { yield }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Sets $VERBOSE to +true+ for the duration of the block and back to its
|
|
17
|
+
# original value afterwards.
|
|
18
|
+
def enable_warnings
|
|
19
|
+
with_warnings(true) { yield }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Sets $VERBOSE for the duration of the block and back to its original
|
|
23
|
+
# value afterwards.
|
|
24
|
+
def with_warnings(flag)
|
|
25
|
+
old_verbose, $VERBOSE = $VERBOSE, flag
|
|
26
|
+
yield
|
|
27
|
+
ensure
|
|
28
|
+
$VERBOSE = old_verbose
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Blocks and ignores any exception passed as argument if raised within the block.
|
|
32
|
+
#
|
|
33
|
+
# suppress(ZeroDivisionError) do
|
|
34
|
+
# 1/0
|
|
35
|
+
# puts 'This code is NOT reached'
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# puts 'This code gets executed and nothing related to ZeroDivisionError was seen'
|
|
39
|
+
def suppress(*exception_classes)
|
|
40
|
+
yield
|
|
41
|
+
rescue *exception_classes
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
class Module
|
|
2
|
+
# Allows you to make aliases for attributes, which includes
|
|
3
|
+
# getter, setter, and a predicate.
|
|
4
|
+
#
|
|
5
|
+
# class Content < ActiveRecord::Base
|
|
6
|
+
# # has a title attribute
|
|
7
|
+
# end
|
|
8
|
+
#
|
|
9
|
+
# class Email < Content
|
|
10
|
+
# alias_attribute :subject, :title
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# e = Email.find(1)
|
|
14
|
+
# e.title # => "Superstars"
|
|
15
|
+
# e.subject # => "Superstars"
|
|
16
|
+
# e.subject? # => true
|
|
17
|
+
# e.subject = "Megastars"
|
|
18
|
+
# e.title # => "Megastars"
|
|
19
|
+
def alias_attribute(new_name, old_name)
|
|
20
|
+
# The following reader methods use an explicit `self` receiver in order to
|
|
21
|
+
# support aliases that start with an uppercase letter. Otherwise, they would
|
|
22
|
+
# be resolved as constants instead.
|
|
23
|
+
module_eval <<-STR, __FILE__, __LINE__ + 1
|
|
24
|
+
def #{new_name}; self.#{old_name}; end # def subject; self.title; end
|
|
25
|
+
def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end
|
|
26
|
+
def #{new_name}=(v); self.#{old_name} = v; end # def subject=(v); self.title = v; end
|
|
27
|
+
STR
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class Module
|
|
2
|
+
# A module may or may not have a name.
|
|
3
|
+
#
|
|
4
|
+
# module M; end
|
|
5
|
+
# M.name # => "M"
|
|
6
|
+
#
|
|
7
|
+
# m = Module.new
|
|
8
|
+
# m.name # => nil
|
|
9
|
+
#
|
|
10
|
+
# +anonymous?+ method returns true if module does not have a name, false otherwise:
|
|
11
|
+
#
|
|
12
|
+
# Module.new.anonymous? # => true
|
|
13
|
+
#
|
|
14
|
+
# module M; end
|
|
15
|
+
# M.anonymous? # => false
|
|
16
|
+
#
|
|
17
|
+
# A module gets a name when it is first assigned to a constant. Either
|
|
18
|
+
# via the +module+ or +class+ keyword or by an explicit assignment:
|
|
19
|
+
#
|
|
20
|
+
# m = Module.new # creates an anonymous module
|
|
21
|
+
# m.anonymous? # => true
|
|
22
|
+
# M = m # m gets a name here as a side-effect
|
|
23
|
+
# m.name # => "M"
|
|
24
|
+
# m.anonymous? # => false
|
|
25
|
+
def anonymous?
|
|
26
|
+
name.nil?
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class Module
|
|
2
|
+
# Declares an attribute reader backed by an internally-named instance variable.
|
|
3
|
+
def attr_internal_reader(*attrs)
|
|
4
|
+
attrs.each { |attr_name| attr_internal_define(attr_name, :reader) }
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Declares an attribute writer backed by an internally-named instance variable.
|
|
8
|
+
def attr_internal_writer(*attrs)
|
|
9
|
+
attrs.each { |attr_name| attr_internal_define(attr_name, :writer) }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Declares an attribute reader and writer backed by an internally-named instance
|
|
13
|
+
# variable.
|
|
14
|
+
def attr_internal_accessor(*attrs)
|
|
15
|
+
attr_internal_reader(*attrs)
|
|
16
|
+
attr_internal_writer(*attrs)
|
|
17
|
+
end
|
|
18
|
+
alias_method :attr_internal, :attr_internal_accessor
|
|
19
|
+
|
|
20
|
+
class << self; attr_accessor :attr_internal_naming_format end
|
|
21
|
+
self.attr_internal_naming_format = "@_%s"
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
def attr_internal_ivar_name(attr)
|
|
25
|
+
Module.attr_internal_naming_format % attr
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def attr_internal_define(attr_name, type)
|
|
29
|
+
internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, "")
|
|
30
|
+
# use native attr_* methods as they are faster on some Ruby implementations
|
|
31
|
+
send("attr_#{type}", internal_name)
|
|
32
|
+
attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
|
|
33
|
+
alias_method attr_name, internal_name
|
|
34
|
+
remove_method internal_name
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Extends the module object with class/module and instance accessors for
|
|
2
|
+
# class/module attributes, just like the native attr* accessors for instance
|
|
3
|
+
# attributes.
|
|
4
|
+
class Module
|
|
5
|
+
# Defines a class attribute and creates a class and instance reader methods.
|
|
6
|
+
# The underlying class variable is set to +nil+, if it is not previously
|
|
7
|
+
# defined. All class and instance methods created will be public, even if
|
|
8
|
+
# this method is called with a private or protected access modifier.
|
|
9
|
+
#
|
|
10
|
+
# module HairColors
|
|
11
|
+
# mattr_reader :hair_colors
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# HairColors.hair_colors # => nil
|
|
15
|
+
# HairColors.class_variable_set("@@hair_colors", [:brown, :black])
|
|
16
|
+
# HairColors.hair_colors # => [:brown, :black]
|
|
17
|
+
#
|
|
18
|
+
# The attribute name must be a valid method name in Ruby.
|
|
19
|
+
#
|
|
20
|
+
# module Foo
|
|
21
|
+
# mattr_reader :"1_Badname"
|
|
22
|
+
# end
|
|
23
|
+
# # => NameError: invalid attribute name: 1_Badname
|
|
24
|
+
#
|
|
25
|
+
# To omit the instance reader method, pass
|
|
26
|
+
# <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
|
|
27
|
+
#
|
|
28
|
+
# module HairColors
|
|
29
|
+
# mattr_reader :hair_colors, instance_reader: false
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# class Person
|
|
33
|
+
# include HairColors
|
|
34
|
+
# end
|
|
35
|
+
#
|
|
36
|
+
# Person.new.hair_colors # => NoMethodError
|
|
37
|
+
#
|
|
38
|
+
# You can set a default value for the attribute.
|
|
39
|
+
#
|
|
40
|
+
# module HairColors
|
|
41
|
+
# mattr_reader :hair_colors, default: [:brown, :black, :blonde, :red]
|
|
42
|
+
# end
|
|
43
|
+
#
|
|
44
|
+
# class Person
|
|
45
|
+
# include HairColors
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
|
|
49
|
+
def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil)
|
|
50
|
+
syms.each do |sym|
|
|
51
|
+
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
|
|
52
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
|
53
|
+
@@#{sym} = nil unless defined? @@#{sym}
|
|
54
|
+
def self.#{sym}
|
|
55
|
+
@@#{sym}
|
|
56
|
+
end
|
|
57
|
+
EOS
|
|
58
|
+
|
|
59
|
+
if instance_reader && instance_accessor
|
|
60
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
|
61
|
+
def #{sym}
|
|
62
|
+
@@#{sym}
|
|
63
|
+
end
|
|
64
|
+
EOS
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
sym_default_value = (block_given? && default.nil?) ? yield : default
|
|
68
|
+
class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil?
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
alias :cattr_reader :mattr_reader
|
|
72
|
+
|
|
73
|
+
# Defines a class attribute and creates a class and instance writer methods to
|
|
74
|
+
# allow assignment to the attribute. All class and instance methods created
|
|
75
|
+
# will be public, even if this method is called with a private or protected
|
|
76
|
+
# access modifier.
|
|
77
|
+
#
|
|
78
|
+
# module HairColors
|
|
79
|
+
# mattr_writer :hair_colors
|
|
80
|
+
# end
|
|
81
|
+
#
|
|
82
|
+
# class Person
|
|
83
|
+
# include HairColors
|
|
84
|
+
# end
|
|
85
|
+
#
|
|
86
|
+
# HairColors.hair_colors = [:brown, :black]
|
|
87
|
+
# Person.class_variable_get("@@hair_colors") # => [:brown, :black]
|
|
88
|
+
# Person.new.hair_colors = [:blonde, :red]
|
|
89
|
+
# HairColors.class_variable_get("@@hair_colors") # => [:blonde, :red]
|
|
90
|
+
#
|
|
91
|
+
# To omit the instance writer method, pass
|
|
92
|
+
# <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
|
|
93
|
+
#
|
|
94
|
+
# module HairColors
|
|
95
|
+
# mattr_writer :hair_colors, instance_writer: false
|
|
96
|
+
# end
|
|
97
|
+
#
|
|
98
|
+
# class Person
|
|
99
|
+
# include HairColors
|
|
100
|
+
# end
|
|
101
|
+
#
|
|
102
|
+
# Person.new.hair_colors = [:blonde, :red] # => NoMethodError
|
|
103
|
+
#
|
|
104
|
+
# You can set a default value for the attribute.
|
|
105
|
+
#
|
|
106
|
+
# module HairColors
|
|
107
|
+
# mattr_writer :hair_colors, default: [:brown, :black, :blonde, :red]
|
|
108
|
+
# end
|
|
109
|
+
#
|
|
110
|
+
# class Person
|
|
111
|
+
# include HairColors
|
|
112
|
+
# end
|
|
113
|
+
#
|
|
114
|
+
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
|
|
115
|
+
def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil)
|
|
116
|
+
syms.each do |sym|
|
|
117
|
+
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
|
|
118
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
|
119
|
+
@@#{sym} = nil unless defined? @@#{sym}
|
|
120
|
+
def self.#{sym}=(obj)
|
|
121
|
+
@@#{sym} = obj
|
|
122
|
+
end
|
|
123
|
+
EOS
|
|
124
|
+
|
|
125
|
+
if instance_writer && instance_accessor
|
|
126
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
|
127
|
+
def #{sym}=(obj)
|
|
128
|
+
@@#{sym} = obj
|
|
129
|
+
end
|
|
130
|
+
EOS
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
sym_default_value = (block_given? && default.nil?) ? yield : default
|
|
134
|
+
send("#{sym}=", sym_default_value) unless sym_default_value.nil?
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
alias :cattr_writer :mattr_writer
|
|
138
|
+
|
|
139
|
+
# Defines both class and instance accessors for class attributes.
|
|
140
|
+
# All class and instance methods created will be public, even if
|
|
141
|
+
# this method is called with a private or protected access modifier.
|
|
142
|
+
#
|
|
143
|
+
# module HairColors
|
|
144
|
+
# mattr_accessor :hair_colors
|
|
145
|
+
# end
|
|
146
|
+
#
|
|
147
|
+
# class Person
|
|
148
|
+
# include HairColors
|
|
149
|
+
# end
|
|
150
|
+
#
|
|
151
|
+
# HairColors.hair_colors = [:brown, :black, :blonde, :red]
|
|
152
|
+
# HairColors.hair_colors # => [:brown, :black, :blonde, :red]
|
|
153
|
+
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
|
|
154
|
+
#
|
|
155
|
+
# If a subclass changes the value then that would also change the value for
|
|
156
|
+
# parent class. Similarly if parent class changes the value then that would
|
|
157
|
+
# change the value of subclasses too.
|
|
158
|
+
#
|
|
159
|
+
# class Citizen < Person
|
|
160
|
+
# end
|
|
161
|
+
#
|
|
162
|
+
# Citizen.new.hair_colors << :blue
|
|
163
|
+
# Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
|
|
164
|
+
#
|
|
165
|
+
# To omit the instance writer method, pass <tt>instance_writer: false</tt>.
|
|
166
|
+
# To omit the instance reader method, pass <tt>instance_reader: false</tt>.
|
|
167
|
+
#
|
|
168
|
+
# module HairColors
|
|
169
|
+
# mattr_accessor :hair_colors, instance_writer: false, instance_reader: false
|
|
170
|
+
# end
|
|
171
|
+
#
|
|
172
|
+
# class Person
|
|
173
|
+
# include HairColors
|
|
174
|
+
# end
|
|
175
|
+
#
|
|
176
|
+
# Person.new.hair_colors = [:brown] # => NoMethodError
|
|
177
|
+
# Person.new.hair_colors # => NoMethodError
|
|
178
|
+
#
|
|
179
|
+
# Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
|
|
180
|
+
#
|
|
181
|
+
# module HairColors
|
|
182
|
+
# mattr_accessor :hair_colors, instance_accessor: false
|
|
183
|
+
# end
|
|
184
|
+
#
|
|
185
|
+
# class Person
|
|
186
|
+
# include HairColors
|
|
187
|
+
# end
|
|
188
|
+
#
|
|
189
|
+
# Person.new.hair_colors = [:brown] # => NoMethodError
|
|
190
|
+
# Person.new.hair_colors # => NoMethodError
|
|
191
|
+
#
|
|
192
|
+
# You can set a default value for the attribute.
|
|
193
|
+
#
|
|
194
|
+
# module HairColors
|
|
195
|
+
# mattr_accessor :hair_colors, default: [:brown, :black, :blonde, :red]
|
|
196
|
+
# end
|
|
197
|
+
#
|
|
198
|
+
# class Person
|
|
199
|
+
# include HairColors
|
|
200
|
+
# end
|
|
201
|
+
#
|
|
202
|
+
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
|
|
203
|
+
def mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk)
|
|
204
|
+
mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default, &blk)
|
|
205
|
+
mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor, default: default)
|
|
206
|
+
end
|
|
207
|
+
alias :cattr_accessor :mattr_accessor
|
|
208
|
+
end
|