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.
Files changed (116) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +17 -0
  3. data/Gemfile +6 -0
  4. data/LICENSE.md +0 -0
  5. data/README.md +0 -0
  6. data/bin/ctxirb +156 -0
  7. data/lib/git.rb +166 -0
  8. data/lib/git/LICENSE +21 -0
  9. data/lib/git/author.rb +14 -0
  10. data/lib/git/base.rb +551 -0
  11. data/lib/git/base/factory.rb +75 -0
  12. data/lib/git/branch.rb +126 -0
  13. data/lib/git/branches.rb +71 -0
  14. data/lib/git/config.rb +22 -0
  15. data/lib/git/diff.rb +159 -0
  16. data/lib/git/index.rb +5 -0
  17. data/lib/git/lib.rb +1041 -0
  18. data/lib/git/log.rb +128 -0
  19. data/lib/git/object.rb +312 -0
  20. data/lib/git/path.rb +31 -0
  21. data/lib/git/remote.rb +36 -0
  22. data/lib/git/repository.rb +6 -0
  23. data/lib/git/stash.rb +27 -0
  24. data/lib/git/stashes.rb +55 -0
  25. data/lib/git/status.rb +199 -0
  26. data/lib/git/version.rb +5 -0
  27. data/lib/git/working_directory.rb +4 -0
  28. data/lib/sigterm_extensions.rb +75 -0
  29. data/lib/sigterm_extensions/all.rb +12 -0
  30. data/lib/sigterm_extensions/backtrace_cleaner.rb +129 -0
  31. data/lib/sigterm_extensions/callbacks.rb +847 -0
  32. data/lib/sigterm_extensions/concern.rb +169 -0
  33. data/lib/sigterm_extensions/configurable.rb +38 -0
  34. data/lib/sigterm_extensions/core_ext.rb +4 -0
  35. data/lib/sigterm_extensions/core_ext/array.rb +3 -0
  36. data/lib/sigterm_extensions/core_ext/array/extract.rb +19 -0
  37. data/lib/sigterm_extensions/core_ext/array/extract_options.rb +29 -0
  38. data/lib/sigterm_extensions/core_ext/class.rb +3 -0
  39. data/lib/sigterm_extensions/core_ext/class/attribute.rb +139 -0
  40. data/lib/sigterm_extensions/core_ext/class/attribute_accessors.rb +4 -0
  41. data/lib/sigterm_extensions/core_ext/class/subclasses.rb +52 -0
  42. data/lib/sigterm_extensions/core_ext/custom.rb +12 -0
  43. data/lib/sigterm_extensions/core_ext/digest.rb +3 -0
  44. data/lib/sigterm_extensions/core_ext/digest/uuid.rb +51 -0
  45. data/lib/sigterm_extensions/core_ext/enumerable.rb +232 -0
  46. data/lib/sigterm_extensions/core_ext/file.rb +3 -0
  47. data/lib/sigterm_extensions/core_ext/file/atomic.rb +68 -0
  48. data/lib/sigterm_extensions/core_ext/hash.rb +3 -0
  49. data/lib/sigterm_extensions/core_ext/hash/deep_merge.rb +41 -0
  50. data/lib/sigterm_extensions/core_ext/hash/deep_transform_values.rb +44 -0
  51. data/lib/sigterm_extensions/core_ext/hash/except.rb +22 -0
  52. data/lib/sigterm_extensions/core_ext/hash/keys.rb +141 -0
  53. data/lib/sigterm_extensions/core_ext/hash/reverse_merge.rb +23 -0
  54. data/lib/sigterm_extensions/core_ext/hash/slice.rb +24 -0
  55. data/lib/sigterm_extensions/core_ext/kernel.rb +3 -0
  56. data/lib/sigterm_extensions/core_ext/kernel/concern.rb +12 -0
  57. data/lib/sigterm_extensions/core_ext/kernel/reporting.rb +43 -0
  58. data/lib/sigterm_extensions/core_ext/kernel/singleton_class.rb +6 -0
  59. data/lib/sigterm_extensions/core_ext/load_error.rb +7 -0
  60. data/lib/sigterm_extensions/core_ext/module.rb +3 -0
  61. data/lib/sigterm_extensions/core_ext/module/aliasing.rb +29 -0
  62. data/lib/sigterm_extensions/core_ext/module/anonymous.rb +28 -0
  63. data/lib/sigterm_extensions/core_ext/module/attr_internal.rb +36 -0
  64. data/lib/sigterm_extensions/core_ext/module/attribute_accessors.rb +208 -0
  65. data/lib/sigterm_extensions/core_ext/module/attribute_accessors_per_thread.rb +146 -0
  66. data/lib/sigterm_extensions/core_ext/module/concerning.rb +132 -0
  67. data/lib/sigterm_extensions/core_ext/module/delegation.rb +319 -0
  68. data/lib/sigterm_extensions/core_ext/module/redefine_method.rb +38 -0
  69. data/lib/sigterm_extensions/core_ext/module/remove_method.rb +15 -0
  70. data/lib/sigterm_extensions/core_ext/name_error.rb +36 -0
  71. data/lib/sigterm_extensions/core_ext/object.rb +3 -0
  72. data/lib/sigterm_extensions/core_ext/object/blank.rb +153 -0
  73. data/lib/sigterm_extensions/core_ext/object/colors.rb +39 -0
  74. data/lib/sigterm_extensions/core_ext/object/duplicable.rb +47 -0
  75. data/lib/sigterm_extensions/core_ext/object/inclusion.rb +27 -0
  76. data/lib/sigterm_extensions/core_ext/object/instance_variables.rb +28 -0
  77. data/lib/sigterm_extensions/core_ext/object/methods.rb +61 -0
  78. data/lib/sigterm_extensions/core_ext/object/with_options.rb +80 -0
  79. data/lib/sigterm_extensions/core_ext/range.rb +3 -0
  80. data/lib/sigterm_extensions/core_ext/range/compare_range.rb +74 -0
  81. data/lib/sigterm_extensions/core_ext/range/conversions.rb +39 -0
  82. data/lib/sigterm_extensions/core_ext/range/overlaps.rb +8 -0
  83. data/lib/sigterm_extensions/core_ext/securerandom.rb +43 -0
  84. data/lib/sigterm_extensions/core_ext/string.rb +3 -0
  85. data/lib/sigterm_extensions/core_ext/string/access.rb +93 -0
  86. data/lib/sigterm_extensions/core_ext/string/filters.rb +143 -0
  87. data/lib/sigterm_extensions/core_ext/string/starts_ends_with.rb +4 -0
  88. data/lib/sigterm_extensions/core_ext/string/strip.rb +25 -0
  89. data/lib/sigterm_extensions/core_ext/tryable.rb +132 -0
  90. data/lib/sigterm_extensions/descendants_tracker.rb +108 -0
  91. data/lib/sigterm_extensions/gem_methods.rb +47 -0
  92. data/lib/sigterm_extensions/hash_binding.rb +16 -0
  93. data/lib/sigterm_extensions/inflector.rb +339 -0
  94. data/lib/sigterm_extensions/inflector/acronyms.rb +42 -0
  95. data/lib/sigterm_extensions/inflector/inflections.rb +249 -0
  96. data/lib/sigterm_extensions/inflector/inflections/defaults.rb +117 -0
  97. data/lib/sigterm_extensions/inflector/rules.rb +37 -0
  98. data/lib/sigterm_extensions/inflector/version.rb +8 -0
  99. data/lib/sigterm_extensions/interactive_editor.rb +120 -0
  100. data/lib/sigterm_extensions/lazy.rb +34 -0
  101. data/lib/sigterm_extensions/lazy_load_hooks.rb +79 -0
  102. data/lib/sigterm_extensions/option_merger.rb +32 -0
  103. data/lib/sigterm_extensions/ordered_hash.rb +48 -0
  104. data/lib/sigterm_extensions/ordered_options.rb +83 -0
  105. data/lib/sigterm_extensions/paths.rb +235 -0
  106. data/lib/sigterm_extensions/per_thread_registry.rb +58 -0
  107. data/lib/sigterm_extensions/proxy_object.rb +14 -0
  108. data/lib/sigterm_extensions/staging/boot.rb +31 -0
  109. data/lib/sigterm_extensions/staging/boot/bundler_patch.rb +24 -0
  110. data/lib/sigterm_extensions/staging/boot/command.rb +26 -0
  111. data/lib/sigterm_extensions/staging/boot/gemfile_next_auto_sync.rb +79 -0
  112. data/lib/sigterm_extensions/version.rb +4 -0
  113. data/lib/sigterm_extensions/wrappable.rb +16 -0
  114. data/sigterm_extensions.gemspec +42 -0
  115. data/templates/dotpryrc.rb.erb +124 -0
  116. 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,3 @@
1
+ Dir.glob(File.expand_path('kernel/*.rb', __dir__)).each do |path|
2
+ require path
3
+ 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,6 @@
1
+ module Kernel
2
+ # class_eval on an object acts like singleton_class.class_eval.
3
+ def class_eval(*args, &block)
4
+ singleton_class.class_eval(*args, &block)
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ class LoadError
2
+ # Returns true if the given path name (except perhaps for the ".rb"
3
+ # extension) is the missing file which caused the exception to be raised.
4
+ def is_missing?(location)
5
+ location.sub(/\.rb$/, "") == path.to_s.sub(/\.rb$/, "")
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ Dir.glob(File.expand_path('module/*.rb', __dir__)).each do |path|
2
+ require path
3
+ 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