sigterm_extensions 0.0.4

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