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,169 @@
|
|
|
1
|
+
module SigtermExtensions
|
|
2
|
+
# A typical module looks like this:
|
|
3
|
+
#
|
|
4
|
+
# module M
|
|
5
|
+
# def self.included(base)
|
|
6
|
+
# base.extend ClassMethods
|
|
7
|
+
# base.class_eval do
|
|
8
|
+
# scope :disabled, -> { where(disabled: true) }
|
|
9
|
+
# end
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
# module ClassMethods
|
|
13
|
+
# ...
|
|
14
|
+
# end
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# By using <tt>SigtermExtensions::Concern</tt> the above module could instead be
|
|
18
|
+
# written as:
|
|
19
|
+
#
|
|
20
|
+
# require 'sigterm_extensions/concern'
|
|
21
|
+
#
|
|
22
|
+
# module M
|
|
23
|
+
# extend SigtermExtensions::Concern
|
|
24
|
+
#
|
|
25
|
+
# included do
|
|
26
|
+
# scope :disabled, -> { where(disabled: true) }
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# class_methods do
|
|
30
|
+
# ...
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# Moreover, it gracefully handles module dependencies. Given a +Foo+ module
|
|
35
|
+
# and a +Bar+ module which depends on the former, we would typically write the
|
|
36
|
+
# following:
|
|
37
|
+
#
|
|
38
|
+
# module Foo
|
|
39
|
+
# def self.included(base)
|
|
40
|
+
# base.class_eval do
|
|
41
|
+
# def self.method_injected_by_foo
|
|
42
|
+
# ...
|
|
43
|
+
# end
|
|
44
|
+
# end
|
|
45
|
+
# end
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# module Bar
|
|
49
|
+
# def self.included(base)
|
|
50
|
+
# base.method_injected_by_foo
|
|
51
|
+
# end
|
|
52
|
+
# end
|
|
53
|
+
#
|
|
54
|
+
# class Host
|
|
55
|
+
# include Foo # We need to include this dependency for Bar
|
|
56
|
+
# include Bar # Bar is the module that Host really needs
|
|
57
|
+
# end
|
|
58
|
+
#
|
|
59
|
+
# But why should +Host+ care about +Bar+'s dependencies, namely +Foo+? We
|
|
60
|
+
# could try to hide these from +Host+ directly including +Foo+ in +Bar+:
|
|
61
|
+
#
|
|
62
|
+
# module Bar
|
|
63
|
+
# include Foo
|
|
64
|
+
# def self.included(base)
|
|
65
|
+
# base.method_injected_by_foo
|
|
66
|
+
# end
|
|
67
|
+
# end
|
|
68
|
+
#
|
|
69
|
+
# class Host
|
|
70
|
+
# include Bar
|
|
71
|
+
# end
|
|
72
|
+
#
|
|
73
|
+
# Unfortunately this won't work, since when +Foo+ is included, its <tt>base</tt>
|
|
74
|
+
# is the +Bar+ module, not the +Host+ class. With <tt>SigtermExtensions::Concern</tt>,
|
|
75
|
+
# module dependencies are properly resolved:
|
|
76
|
+
#
|
|
77
|
+
# require 'sigterm_extensions/concern'
|
|
78
|
+
#
|
|
79
|
+
# module Foo
|
|
80
|
+
# extend SigtermExtensions::Concern
|
|
81
|
+
# included do
|
|
82
|
+
# def self.method_injected_by_foo
|
|
83
|
+
# ...
|
|
84
|
+
# end
|
|
85
|
+
# end
|
|
86
|
+
# end
|
|
87
|
+
#
|
|
88
|
+
# module Bar
|
|
89
|
+
# extend SigtermExtensions::Concern
|
|
90
|
+
# include Foo
|
|
91
|
+
#
|
|
92
|
+
# included do
|
|
93
|
+
# self.method_injected_by_foo
|
|
94
|
+
# end
|
|
95
|
+
# end
|
|
96
|
+
#
|
|
97
|
+
# class Host
|
|
98
|
+
# include Bar # It works, now Bar takes care of its dependencies
|
|
99
|
+
# end
|
|
100
|
+
module Concern
|
|
101
|
+
class MultipleIncludedBlocks < StandardError #:nodoc:
|
|
102
|
+
def initialize
|
|
103
|
+
super "Cannot define multiple 'included' blocks for a Concern"
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.extended(base) #:nodoc:
|
|
108
|
+
base.instance_variable_set(:@_dependencies, [])
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def append_features(base) #:nodoc:
|
|
112
|
+
if base.instance_variable_defined?(:@_dependencies)
|
|
113
|
+
base.instance_variable_get(:@_dependencies) << self
|
|
114
|
+
false
|
|
115
|
+
else
|
|
116
|
+
return false if base < self
|
|
117
|
+
@_dependencies.each { |dep| base.include(dep) }
|
|
118
|
+
super
|
|
119
|
+
base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
|
|
120
|
+
base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Evaluate given block in context of base class,
|
|
125
|
+
# so that you can write class macros here.
|
|
126
|
+
# When you define more than one +included+ block, it raises an exception.
|
|
127
|
+
def included(base = nil, &block)
|
|
128
|
+
if base.nil?
|
|
129
|
+
if instance_variable_defined?(:@_included_block)
|
|
130
|
+
if @_included_block.source_location != block.source_location
|
|
131
|
+
raise MultipleIncludedBlocks
|
|
132
|
+
end
|
|
133
|
+
else
|
|
134
|
+
@_included_block = block
|
|
135
|
+
end
|
|
136
|
+
else
|
|
137
|
+
super
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Define class methods from given block.
|
|
142
|
+
# You can define private class methods as well.
|
|
143
|
+
#
|
|
144
|
+
# module Example
|
|
145
|
+
# extend ActiveSupport::Concern
|
|
146
|
+
#
|
|
147
|
+
# class_methods do
|
|
148
|
+
# def foo; puts 'foo'; end
|
|
149
|
+
#
|
|
150
|
+
# private
|
|
151
|
+
# def bar; puts 'bar'; end
|
|
152
|
+
# end
|
|
153
|
+
# end
|
|
154
|
+
#
|
|
155
|
+
# class Buzz
|
|
156
|
+
# include Example
|
|
157
|
+
# end
|
|
158
|
+
#
|
|
159
|
+
# Buzz.foo # => "foo"
|
|
160
|
+
# Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
|
|
161
|
+
def class_methods(&class_methods_module_definition)
|
|
162
|
+
mod = const_defined?(:ClassMethods, false) ?
|
|
163
|
+
const_get(:ClassMethods) :
|
|
164
|
+
const_set(:ClassMethods, Module.new)
|
|
165
|
+
|
|
166
|
+
mod.module_eval(&class_methods_module_definition)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module SigtermExtensions
|
|
2
|
+
module Configurable
|
|
3
|
+
def self.with(*attrs)
|
|
4
|
+
not_provided = Object.new
|
|
5
|
+
|
|
6
|
+
config_class = Class.new do
|
|
7
|
+
attrs.each do |attr|
|
|
8
|
+
define_method attr do |value = not_provided, &block|
|
|
9
|
+
if value === not_provided && block.nil?
|
|
10
|
+
result = instance_variable_get("@#{attr}")
|
|
11
|
+
result.is_a?(Proc) ? instance_eval(&result) : result
|
|
12
|
+
else
|
|
13
|
+
instance_variable_set("@#{attr}", block || value)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
attr_writer *attrs
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class_methods = Module.new do
|
|
22
|
+
define_method :config do
|
|
23
|
+
@config ||= config_class.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def configure(&block)
|
|
27
|
+
config.instance_eval(&block)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Module.new do
|
|
32
|
+
singleton_class.send :define_method, :included do |host_class|
|
|
33
|
+
host_class.extend class_methods
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
class Array
|
|
2
|
+
# Removes and returns the elements for which the block returns a true value.
|
|
3
|
+
# If no block is given, an Enumerator is returned instead.
|
|
4
|
+
#
|
|
5
|
+
# numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
6
|
+
# odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
|
|
7
|
+
# numbers # => [0, 2, 4, 6, 8]
|
|
8
|
+
def extract!
|
|
9
|
+
return to_enum(:extract!) { size } unless block_given?
|
|
10
|
+
|
|
11
|
+
extracted_elements = []
|
|
12
|
+
|
|
13
|
+
reject! do |element|
|
|
14
|
+
extracted_elements << element if yield(element)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
extracted_elements
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
class Hash
|
|
2
|
+
# By default, only instances of Hash itself are extractable.
|
|
3
|
+
# Subclasses of Hash may implement this method and return
|
|
4
|
+
# true to declare themselves as extractable. If a Hash
|
|
5
|
+
# is extractable, Array#extract_options! pops it from
|
|
6
|
+
# the Array when it is the last element of the Array.
|
|
7
|
+
def extractable_options?
|
|
8
|
+
instance_of?(Hash)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Array
|
|
13
|
+
# Extracts options from a set of arguments. Removes and returns the last
|
|
14
|
+
# element in the array if it's a hash, otherwise returns a blank hash.
|
|
15
|
+
#
|
|
16
|
+
# def options(*args)
|
|
17
|
+
# args.extract_options!
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# options(1, 2) # => {}
|
|
21
|
+
# options(1, 2, a: :b) # => {:a=>:b}
|
|
22
|
+
def extract_options!
|
|
23
|
+
if last.is_a?(Hash) && last.extractable_options?
|
|
24
|
+
pop
|
|
25
|
+
else
|
|
26
|
+
{}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
require "sigterm_extensions/core_ext/kernel/singleton_class"
|
|
2
|
+
require "sigterm_extensions/core_ext/module/redefine_method"
|
|
3
|
+
require "sigterm_extensions/core_ext/array/extract_options"
|
|
4
|
+
|
|
5
|
+
class Class
|
|
6
|
+
# Declare a class-level attribute whose value is inheritable by subclasses.
|
|
7
|
+
# Subclasses can change their own value and it will not impact parent class.
|
|
8
|
+
#
|
|
9
|
+
# ==== Options
|
|
10
|
+
#
|
|
11
|
+
# * <tt>:instance_reader</tt> - Sets the instance reader method (defaults to true).
|
|
12
|
+
# * <tt>:instance_writer</tt> - Sets the instance writer method (defaults to true).
|
|
13
|
+
# * <tt>:instance_accessor</tt> - Sets both instance methods (defaults to true).
|
|
14
|
+
# * <tt>:instance_predicate</tt> - Sets a predicate method (defaults to true).
|
|
15
|
+
# * <tt>:default</tt> - Sets a default value for the attribute (defaults to nil).
|
|
16
|
+
#
|
|
17
|
+
# ==== Examples
|
|
18
|
+
#
|
|
19
|
+
# class Base
|
|
20
|
+
# class_attribute :setting
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# class Subclass < Base
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# Base.setting = true
|
|
27
|
+
# Subclass.setting # => true
|
|
28
|
+
# Subclass.setting = false
|
|
29
|
+
# Subclass.setting # => false
|
|
30
|
+
# Base.setting # => true
|
|
31
|
+
#
|
|
32
|
+
# In the above case as long as Subclass does not assign a value to setting
|
|
33
|
+
# by performing <tt>Subclass.setting = _something_</tt>, <tt>Subclass.setting</tt>
|
|
34
|
+
# would read value assigned to parent class. Once Subclass assigns a value then
|
|
35
|
+
# the value assigned by Subclass would be returned.
|
|
36
|
+
#
|
|
37
|
+
# This matches normal Ruby method inheritance: think of writing an attribute
|
|
38
|
+
# on a subclass as overriding the reader method. However, you need to be aware
|
|
39
|
+
# when using +class_attribute+ with mutable structures as +Array+ or +Hash+.
|
|
40
|
+
# In such cases, you don't want to do changes in place. Instead use setters:
|
|
41
|
+
#
|
|
42
|
+
# Base.setting = []
|
|
43
|
+
# Base.setting # => []
|
|
44
|
+
# Subclass.setting # => []
|
|
45
|
+
#
|
|
46
|
+
# # Appending in child changes both parent and child because it is the same object:
|
|
47
|
+
# Subclass.setting << :foo
|
|
48
|
+
# Base.setting # => [:foo]
|
|
49
|
+
# Subclass.setting # => [:foo]
|
|
50
|
+
#
|
|
51
|
+
# # Use setters to not propagate changes:
|
|
52
|
+
# Base.setting = []
|
|
53
|
+
# Subclass.setting += [:foo]
|
|
54
|
+
# Base.setting # => []
|
|
55
|
+
# Subclass.setting # => [:foo]
|
|
56
|
+
#
|
|
57
|
+
# For convenience, an instance predicate method is defined as well.
|
|
58
|
+
# To skip it, pass <tt>instance_predicate: false</tt>.
|
|
59
|
+
#
|
|
60
|
+
# Subclass.setting? # => false
|
|
61
|
+
#
|
|
62
|
+
# Instances may overwrite the class value in the same way:
|
|
63
|
+
#
|
|
64
|
+
# Base.setting = true
|
|
65
|
+
# object = Base.new
|
|
66
|
+
# object.setting # => true
|
|
67
|
+
# object.setting = false
|
|
68
|
+
# object.setting # => false
|
|
69
|
+
# Base.setting # => true
|
|
70
|
+
#
|
|
71
|
+
# To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
|
|
72
|
+
#
|
|
73
|
+
# object.setting # => NoMethodError
|
|
74
|
+
# object.setting? # => NoMethodError
|
|
75
|
+
#
|
|
76
|
+
# To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
|
|
77
|
+
#
|
|
78
|
+
# object.setting = false # => NoMethodError
|
|
79
|
+
#
|
|
80
|
+
# To opt out of both instance methods, pass <tt>instance_accessor: false</tt>.
|
|
81
|
+
#
|
|
82
|
+
# To set a default value for the attribute, pass <tt>default:</tt>, like so:
|
|
83
|
+
#
|
|
84
|
+
# class_attribute :settings, default: {}
|
|
85
|
+
def class_attribute(
|
|
86
|
+
*attrs,
|
|
87
|
+
instance_accessor: true,
|
|
88
|
+
instance_reader: instance_accessor,
|
|
89
|
+
instance_writer: instance_accessor,
|
|
90
|
+
instance_predicate: true,
|
|
91
|
+
default: nil
|
|
92
|
+
)
|
|
93
|
+
attrs.each do |name|
|
|
94
|
+
singleton_class.silence_redefinition_of_method(name)
|
|
95
|
+
define_singleton_method(name) { default }
|
|
96
|
+
|
|
97
|
+
singleton_class.silence_redefinition_of_method("#{name}?")
|
|
98
|
+
define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
|
|
99
|
+
|
|
100
|
+
ivar = "@#{name}".to_sym
|
|
101
|
+
|
|
102
|
+
singleton_class.silence_redefinition_of_method("#{name}=")
|
|
103
|
+
define_singleton_method("#{name}=") do |val|
|
|
104
|
+
redefine_singleton_method(name) { val }
|
|
105
|
+
|
|
106
|
+
if singleton_class?
|
|
107
|
+
class_eval do
|
|
108
|
+
redefine_method(name) do
|
|
109
|
+
if instance_variable_defined? ivar
|
|
110
|
+
instance_variable_get ivar
|
|
111
|
+
else
|
|
112
|
+
singleton_class.send name
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
val
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
if instance_reader
|
|
121
|
+
redefine_method(name) do
|
|
122
|
+
if instance_variable_defined?(ivar)
|
|
123
|
+
instance_variable_get ivar
|
|
124
|
+
else
|
|
125
|
+
self.class.public_send name
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
redefine_method("#{name}?") { !!public_send(name) } if instance_predicate
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
if instance_writer
|
|
133
|
+
redefine_method("#{name}=") do |val|
|
|
134
|
+
instance_variable_set ivar, val
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
class Class
|
|
2
|
+
begin
|
|
3
|
+
# Test if this Ruby supports each_object against singleton_class
|
|
4
|
+
ObjectSpace.each_object(Numeric.singleton_class) { }
|
|
5
|
+
|
|
6
|
+
# Returns an array with all classes that are < than its receiver.
|
|
7
|
+
#
|
|
8
|
+
# class C; end
|
|
9
|
+
# C.descendants # => []
|
|
10
|
+
#
|
|
11
|
+
# class B < C; end
|
|
12
|
+
# C.descendants # => [B]
|
|
13
|
+
#
|
|
14
|
+
# class A < B; end
|
|
15
|
+
# C.descendants # => [B, A]
|
|
16
|
+
#
|
|
17
|
+
# class D < C; end
|
|
18
|
+
# C.descendants # => [B, A, D]
|
|
19
|
+
def descendants
|
|
20
|
+
descendants = []
|
|
21
|
+
ObjectSpace.each_object(singleton_class) do |k|
|
|
22
|
+
next if k.singleton_class?
|
|
23
|
+
descendants.unshift k unless k == self
|
|
24
|
+
end
|
|
25
|
+
descendants
|
|
26
|
+
end
|
|
27
|
+
rescue StandardError # JRuby 9.0.4.0 and earlier
|
|
28
|
+
def descendants
|
|
29
|
+
descendants = []
|
|
30
|
+
ObjectSpace.each_object(Class) do |k|
|
|
31
|
+
descendants.unshift k if k < self
|
|
32
|
+
end
|
|
33
|
+
descendants.uniq!
|
|
34
|
+
descendants
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns an array with the direct children of +self+.
|
|
39
|
+
#
|
|
40
|
+
# class Foo; end
|
|
41
|
+
# class Bar < Foo; end
|
|
42
|
+
# class Baz < Bar; end
|
|
43
|
+
#
|
|
44
|
+
# Foo.subclasses # => [Bar]
|
|
45
|
+
def subclasses
|
|
46
|
+
subclasses, chain = [], descendants
|
|
47
|
+
chain.each do |k|
|
|
48
|
+
subclasses << k unless chain.any? { |c| c > k }
|
|
49
|
+
end
|
|
50
|
+
subclasses
|
|
51
|
+
end
|
|
52
|
+
end
|