sigterm_extensions 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|