activesupport-refinements 0.0.1
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.
- data/.gitignore +17 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +32 -0
- data/Rakefile +1 -0
- data/activesupport-refinements.gemspec +21 -0
- data/lib/active_support/refinements/core_ext/array.rb +7 -0
- data/lib/active_support/refinements/core_ext/array/access.rb +56 -0
- data/lib/active_support/refinements/core_ext/array/conversions.rb +224 -0
- data/lib/active_support/refinements/core_ext/array/extract_options.rb +31 -0
- data/lib/active_support/refinements/core_ext/array/grouping.rb +101 -0
- data/lib/active_support/refinements/core_ext/array/prepend_and_append.rb +9 -0
- data/lib/active_support/refinements/core_ext/array/uniq_by.rb +21 -0
- data/lib/active_support/refinements/core_ext/array/wrap.rb +48 -0
- data/lib/active_support/refinements/core_ext/benchmark.rb +7 -0
- data/lib/active_support/refinements/core_ext/big_decimal.rb +1 -0
- data/lib/active_support/refinements/core_ext/big_decimal/conversions.rb +32 -0
- data/lib/active_support/refinements/core_ext/class.rb +4 -0
- data/lib/active_support/refinements/core_ext/class/attribute.rb +119 -0
- data/lib/active_support/refinements/core_ext/class/attribute_accessors.rb +172 -0
- data/lib/active_support/refinements/core_ext/class/delegating_attributes.rb +42 -0
- data/lib/active_support/refinements/core_ext/class/subclasses.rb +44 -0
- data/lib/active_support/refinements/core_ext/date.rb +5 -0
- data/lib/active_support/refinements/core_ext/date/acts_like.rb +10 -0
- data/lib/active_support/refinements/core_ext/date/calculations.rb +123 -0
- data/lib/active_support/refinements/core_ext/date/conversions.rb +86 -0
- data/lib/active_support/refinements/core_ext/date/zones.rb +17 -0
- data/lib/active_support/refinements/core_ext/date_and_time/calculations.rb +232 -0
- data/lib/active_support/refinements/core_ext/date_time.rb +4 -0
- data/lib/active_support/refinements/core_ext/date_time/acts_like.rb +15 -0
- data/lib/active_support/refinements/core_ext/date_time/calculations.rb +143 -0
- data/lib/active_support/refinements/core_ext/date_time/conversions.rb +93 -0
- data/lib/active_support/refinements/core_ext/date_time/zones.rb +26 -0
- data/lib/active_support/refinements/core_ext/enumerable.rb +82 -0
- data/lib/active_support/refinements/core_ext/exception.rb +5 -0
- data/lib/active_support/refinements/core_ext/file.rb +1 -0
- data/lib/active_support/refinements/core_ext/file/atomic.rb +60 -0
- data/lib/active_support/refinements/core_ext/hash.rb +8 -0
- data/lib/active_support/refinements/core_ext/hash/conversions.rb +161 -0
- data/lib/active_support/refinements/core_ext/hash/deep_merge.rb +29 -0
- data/lib/active_support/refinements/core_ext/hash/diff.rb +15 -0
- data/lib/active_support/refinements/core_ext/hash/except.rb +17 -0
- data/lib/active_support/refinements/core_ext/hash/indifferent_access.rb +24 -0
- data/lib/active_support/refinements/core_ext/hash/keys.rb +140 -0
- data/lib/active_support/refinements/core_ext/hash/reverse_merge.rb +24 -0
- data/lib/active_support/refinements/core_ext/hash/slice.rb +42 -0
- data/lib/active_support/refinements/core_ext/integer.rb +3 -0
- data/lib/active_support/refinements/core_ext/integer/inflections.rb +31 -0
- data/lib/active_support/refinements/core_ext/integer/multiple.rb +12 -0
- data/lib/active_support/refinements/core_ext/integer/time.rb +43 -0
- data/lib/active_support/refinements/core_ext/kernel.rb +4 -0
- data/lib/active_support/refinements/core_ext/kernel/agnostics.rb +13 -0
- data/lib/active_support/refinements/core_ext/kernel/debugger.rb +12 -0
- data/lib/active_support/refinements/core_ext/kernel/reporting.rb +97 -0
- data/lib/active_support/refinements/core_ext/kernel/singleton_class.rb +8 -0
- data/lib/active_support/refinements/core_ext/load_error.rb +27 -0
- data/lib/active_support/refinements/core_ext/logger.rb +86 -0
- data/lib/active_support/refinements/core_ext/module.rb +10 -0
- data/lib/active_support/refinements/core_ext/module/aliasing.rb +69 -0
- data/lib/active_support/refinements/core_ext/module/anonymous.rb +21 -0
- data/lib/active_support/refinements/core_ext/module/attr_internal.rb +40 -0
- data/lib/active_support/refinements/core_ext/module/attribute_accessors.rb +68 -0
- data/lib/active_support/refinements/core_ext/module/delegation.rb +172 -0
- data/lib/active_support/refinements/core_ext/module/deprecation.rb +27 -0
- data/lib/active_support/refinements/core_ext/module/introspection.rb +80 -0
- data/lib/active_support/refinements/core_ext/module/qualified_const.rb +54 -0
- data/lib/active_support/refinements/core_ext/module/reachable.rb +10 -0
- data/lib/active_support/refinements/core_ext/module/remove_method.rb +14 -0
- data/lib/active_support/refinements/core_ext/name_error.rb +20 -0
- data/lib/active_support/refinements/core_ext/numeric.rb +3 -0
- data/lib/active_support/refinements/core_ext/numeric/bytes.rb +46 -0
- data/lib/active_support/refinements/core_ext/numeric/conversions.rb +137 -0
- data/lib/active_support/refinements/core_ext/numeric/time.rb +81 -0
- data/lib/active_support/refinements/core_ext/object.rb +14 -0
- data/lib/active_support/refinements/core_ext/object/acts_like.rb +12 -0
- data/lib/active_support/refinements/core_ext/object/blank.rb +107 -0
- data/lib/active_support/refinements/core_ext/object/conversions.rb +4 -0
- data/lib/active_support/refinements/core_ext/object/deep_dup.rb +48 -0
- data/lib/active_support/refinements/core_ext/object/duplicable.rb +92 -0
- data/lib/active_support/refinements/core_ext/object/inclusion.rb +27 -0
- data/lib/active_support/refinements/core_ext/object/instance_variables.rb +30 -0
- data/lib/active_support/refinements/core_ext/object/to_json.rb +27 -0
- data/lib/active_support/refinements/core_ext/object/to_param.rb +60 -0
- data/lib/active_support/refinements/core_ext/object/to_query.rb +29 -0
- data/lib/active_support/refinements/core_ext/object/try.rb +72 -0
- data/lib/active_support/refinements/core_ext/object/with_options.rb +44 -0
- data/lib/active_support/refinements/core_ext/proc.rb +19 -0
- data/lib/active_support/refinements/core_ext/range.rb +3 -0
- data/lib/active_support/refinements/core_ext/range/conversions.rb +21 -0
- data/lib/active_support/refinements/core_ext/range/include_range.rb +23 -0
- data/lib/active_support/refinements/core_ext/range/overlaps.rb +10 -0
- data/lib/active_support/refinements/core_ext/regexp.rb +7 -0
- data/lib/active_support/refinements/core_ext/string.rb +13 -0
- data/lib/active_support/refinements/core_ext/string/access.rb +106 -0
- data/lib/active_support/refinements/core_ext/string/behavior.rb +8 -0
- data/lib/active_support/refinements/core_ext/string/conversions.rb +60 -0
- data/lib/active_support/refinements/core_ext/string/encoding.rb +10 -0
- data/lib/active_support/refinements/core_ext/string/exclude.rb +13 -0
- data/lib/active_support/refinements/core_ext/string/filters.rb +54 -0
- data/lib/active_support/refinements/core_ext/string/indent.rb +45 -0
- data/lib/active_support/refinements/core_ext/string/inflections.rb +214 -0
- data/lib/active_support/refinements/core_ext/string/inquiry.rb +15 -0
- data/lib/active_support/refinements/core_ext/string/multibyte.rb +58 -0
- data/lib/active_support/refinements/core_ext/string/output_safety.rb +194 -0
- data/lib/active_support/refinements/core_ext/string/starts_ends_with.rb +6 -0
- data/lib/active_support/refinements/core_ext/string/strip.rb +28 -0
- data/lib/active_support/refinements/core_ext/string/xchar.rb +18 -0
- data/lib/active_support/refinements/core_ext/time.rb +5 -0
- data/lib/active_support/refinements/core_ext/time/acts_like.rb +10 -0
- data/lib/active_support/refinements/core_ext/time/calculations.rb +251 -0
- data/lib/active_support/refinements/core_ext/time/conversions.rb +65 -0
- data/lib/active_support/refinements/core_ext/time/marshal.rb +30 -0
- data/lib/active_support/refinements/core_ext/time/zones.rb +98 -0
- data/lib/active_support/refinements/core_ext/uri.rb +28 -0
- data/lib/activesupport-refinements.rb +9 -0
- data/lib/activesupport-refinements/version.rb +5 -0
- data/refine_core_ext.rb +45 -0
- data/spec/hwia_spec.rb +15 -0
- data/spec/try_spec.rb +18 -0
- metadata +182 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module ModuleExt; end; module ModuleExt::AttrInternal
|
|
2
|
+
refine Module do
|
|
3
|
+
# Declares an attribute reader backed by an internally-named instance variable.
|
|
4
|
+
def attr_internal_reader(*attrs)
|
|
5
|
+
attrs.each {|attr_name| attr_internal_define(attr_name, :reader)}
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# Declares an attribute writer backed by an internally-named instance variable.
|
|
9
|
+
def attr_internal_writer(*attrs)
|
|
10
|
+
attrs.each {|attr_name| attr_internal_define(attr_name, :writer)}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Declares an attribute reader and writer backed by an internally-named instance
|
|
14
|
+
# variable.
|
|
15
|
+
def attr_internal_accessor(*attrs)
|
|
16
|
+
attr_internal_reader(*attrs)
|
|
17
|
+
attr_internal_writer(*attrs)
|
|
18
|
+
end
|
|
19
|
+
# alias_method :attr_internal, :attr_internal_accessor
|
|
20
|
+
|
|
21
|
+
class << self; attr_accessor :attr_internal_naming_format end
|
|
22
|
+
self.attr_internal_naming_format = '@_%s'
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
def attr_internal_ivar_name(attr)
|
|
26
|
+
Module.attr_internal_naming_format % attr
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def attr_internal_define(attr_name, type)
|
|
30
|
+
internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, '')
|
|
31
|
+
class_eval do # class_eval is necessary on 1.9 or else the methods a made private
|
|
32
|
+
# use native attr_* methods as they are faster on some Ruby implementations
|
|
33
|
+
send("attr_#{type}", internal_name)
|
|
34
|
+
end
|
|
35
|
+
attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
|
|
36
|
+
# alias_method attr_name, internal_name
|
|
37
|
+
remove_method internal_name
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module ModuleExt; end; module ModuleExt::AttributeAccessors
|
|
2
|
+
require 'active_support/refinements/core_ext/array/extract_options'
|
|
3
|
+
|
|
4
|
+
refine Module do
|
|
5
|
+
def mattr_reader(*syms)
|
|
6
|
+
options = syms.extract_options!
|
|
7
|
+
syms.each do |sym|
|
|
8
|
+
raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/
|
|
9
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
|
10
|
+
@@#{sym} = nil unless defined? @@#{sym}
|
|
11
|
+
|
|
12
|
+
def self.#{sym}
|
|
13
|
+
@@#{sym}
|
|
14
|
+
end
|
|
15
|
+
EOS
|
|
16
|
+
|
|
17
|
+
unless options[:instance_reader] == false || options[:instance_accessor] == false
|
|
18
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
|
19
|
+
def #{sym}
|
|
20
|
+
@@#{sym}
|
|
21
|
+
end
|
|
22
|
+
EOS
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def mattr_writer(*syms)
|
|
28
|
+
options = syms.extract_options!
|
|
29
|
+
syms.each do |sym|
|
|
30
|
+
raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/
|
|
31
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
|
32
|
+
def self.#{sym}=(obj)
|
|
33
|
+
@@#{sym} = obj
|
|
34
|
+
end
|
|
35
|
+
EOS
|
|
36
|
+
|
|
37
|
+
unless options[:instance_writer] == false || options[:instance_accessor] == false
|
|
38
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
|
39
|
+
def #{sym}=(obj)
|
|
40
|
+
@@#{sym} = obj
|
|
41
|
+
end
|
|
42
|
+
EOS
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Extends the module object with module and instance accessors for class attributes,
|
|
48
|
+
# just like the native attr* accessors for instance attributes.
|
|
49
|
+
#
|
|
50
|
+
# module AppConfiguration
|
|
51
|
+
# mattr_accessor :google_api_key
|
|
52
|
+
#
|
|
53
|
+
# self.google_api_key = "123456789"
|
|
54
|
+
# end
|
|
55
|
+
#
|
|
56
|
+
# AppConfiguration.google_api_key # => "123456789"
|
|
57
|
+
# AppConfiguration.google_api_key = "overriding the api key!"
|
|
58
|
+
# AppConfiguration.google_api_key # => "overriding the api key!"
|
|
59
|
+
#
|
|
60
|
+
# To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
|
|
61
|
+
# To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
|
|
62
|
+
# To opt out of both instance methods, pass <tt>instance_accessor: false</tt>.
|
|
63
|
+
def mattr_accessor(*syms)
|
|
64
|
+
mattr_reader(*syms)
|
|
65
|
+
mattr_writer(*syms)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
module ModuleExt; end; module ModuleExt::Delegation
|
|
2
|
+
refine Module do
|
|
3
|
+
# Provides a delegate class method to easily expose contained objects' public methods
|
|
4
|
+
# as your own. Pass one or more methods (specified as symbols or strings)
|
|
5
|
+
# and the name of the target object via the <tt>:to</tt> option (also a symbol
|
|
6
|
+
# or string). At least one method and the <tt>:to</tt> option are required.
|
|
7
|
+
#
|
|
8
|
+
# Delegation is particularly useful with Active Record associations:
|
|
9
|
+
#
|
|
10
|
+
# class Greeter < ActiveRecord::Base
|
|
11
|
+
# def hello
|
|
12
|
+
# 'hello'
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# def goodbye
|
|
16
|
+
# 'goodbye'
|
|
17
|
+
# end
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# class Foo < ActiveRecord::Base
|
|
21
|
+
# belongs_to :greeter
|
|
22
|
+
# delegate :hello, to: :greeter
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# Foo.new.hello # => "hello"
|
|
26
|
+
# Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
|
|
27
|
+
#
|
|
28
|
+
# Multiple delegates to the same target are allowed:
|
|
29
|
+
#
|
|
30
|
+
# class Foo < ActiveRecord::Base
|
|
31
|
+
# belongs_to :greeter
|
|
32
|
+
# delegate :hello, :goodbye, to: :greeter
|
|
33
|
+
# end
|
|
34
|
+
#
|
|
35
|
+
# Foo.new.goodbye # => "goodbye"
|
|
36
|
+
#
|
|
37
|
+
# Methods can be delegated to instance variables, class variables, or constants
|
|
38
|
+
# by providing them as a symbols:
|
|
39
|
+
#
|
|
40
|
+
# class Foo
|
|
41
|
+
# CONSTANT_ARRAY = [0,1,2,3]
|
|
42
|
+
# @@class_array = [4,5,6,7]
|
|
43
|
+
#
|
|
44
|
+
# def initialize
|
|
45
|
+
# @instance_array = [8,9,10,11]
|
|
46
|
+
# end
|
|
47
|
+
# delegate :sum, to: :CONSTANT_ARRAY
|
|
48
|
+
# delegate :min, to: :@@class_array
|
|
49
|
+
# delegate :max, to: :@instance_array
|
|
50
|
+
# end
|
|
51
|
+
#
|
|
52
|
+
# Foo.new.sum # => 6
|
|
53
|
+
# Foo.new.min # => 4
|
|
54
|
+
# Foo.new.max # => 11
|
|
55
|
+
#
|
|
56
|
+
# It's also possible to delegate a method to the class by using +:class+:
|
|
57
|
+
#
|
|
58
|
+
# class Foo
|
|
59
|
+
# def self.hello
|
|
60
|
+
# "world"
|
|
61
|
+
# end
|
|
62
|
+
#
|
|
63
|
+
# delegate :hello, to: :class
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
# Foo.new.hello # => "world"
|
|
67
|
+
#
|
|
68
|
+
# Delegates can optionally be prefixed using the <tt>:prefix</tt> option. If the value
|
|
69
|
+
# is <tt>true</tt>, the delegate methods are prefixed with the name of the object being
|
|
70
|
+
# delegated to.
|
|
71
|
+
#
|
|
72
|
+
# Person = Struct.new(:name, :address)
|
|
73
|
+
#
|
|
74
|
+
# class Invoice < Struct.new(:client)
|
|
75
|
+
# delegate :name, :address, to: :client, prefix: true
|
|
76
|
+
# end
|
|
77
|
+
#
|
|
78
|
+
# john_doe = Person.new('John Doe', 'Vimmersvej 13')
|
|
79
|
+
# invoice = Invoice.new(john_doe)
|
|
80
|
+
# invoice.client_name # => "John Doe"
|
|
81
|
+
# invoice.client_address # => "Vimmersvej 13"
|
|
82
|
+
#
|
|
83
|
+
# It is also possible to supply a custom prefix.
|
|
84
|
+
#
|
|
85
|
+
# class Invoice < Struct.new(:client)
|
|
86
|
+
# delegate :name, :address, to: :client, prefix: :customer
|
|
87
|
+
# end
|
|
88
|
+
#
|
|
89
|
+
# invoice = Invoice.new(john_doe)
|
|
90
|
+
# invoice.customer_name # => 'John Doe'
|
|
91
|
+
# invoice.customer_address # => 'Vimmersvej 13'
|
|
92
|
+
#
|
|
93
|
+
# If the delegate object is +nil+ an exception is raised, and that happens
|
|
94
|
+
# no matter whether +nil+ responds to the delegated method. You can get a
|
|
95
|
+
# +nil+ instead with the +:allow_nil+ option.
|
|
96
|
+
#
|
|
97
|
+
# class Foo
|
|
98
|
+
# attr_accessor :bar
|
|
99
|
+
# def initialize(bar = nil)
|
|
100
|
+
# @bar = bar
|
|
101
|
+
# end
|
|
102
|
+
# delegate :zoo, to: :bar
|
|
103
|
+
# end
|
|
104
|
+
#
|
|
105
|
+
# Foo.new.zoo # raises NoMethodError exception (you called nil.zoo)
|
|
106
|
+
#
|
|
107
|
+
# class Foo
|
|
108
|
+
# attr_accessor :bar
|
|
109
|
+
# def initialize(bar = nil)
|
|
110
|
+
# @bar = bar
|
|
111
|
+
# end
|
|
112
|
+
# delegate :zoo, to: :bar, allow_nil: true
|
|
113
|
+
# end
|
|
114
|
+
#
|
|
115
|
+
# Foo.new.zoo # returns nil
|
|
116
|
+
def delegate(*methods)
|
|
117
|
+
options = methods.pop
|
|
118
|
+
unless options.is_a?(Hash) && to = options[:to]
|
|
119
|
+
raise ArgumentError, 'Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
prefix, allow_nil = options.values_at(:prefix, :allow_nil)
|
|
123
|
+
|
|
124
|
+
if prefix == true && to =~ /^[^a-z_]/
|
|
125
|
+
raise ArgumentError, 'Can only automatically set the delegation prefix when delegating to a method.'
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
method_prefix = \
|
|
129
|
+
if prefix
|
|
130
|
+
"#{prefix == true ? to : prefix}_"
|
|
131
|
+
else
|
|
132
|
+
''
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
file, line = caller.first.split(':', 2)
|
|
136
|
+
line = line.to_i
|
|
137
|
+
|
|
138
|
+
to = to.to_s
|
|
139
|
+
to = 'self.class' if to == 'class'
|
|
140
|
+
|
|
141
|
+
methods.each do |method|
|
|
142
|
+
# Attribute writer methods only accept one argument. Makes sure []=
|
|
143
|
+
# methods still accept two arguments.
|
|
144
|
+
definition = (method =~ /[^\]]=$/) ? 'arg' : '*args, &block'
|
|
145
|
+
|
|
146
|
+
if allow_nil
|
|
147
|
+
module_eval(<<-EOS, file, line - 2)
|
|
148
|
+
def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
|
|
149
|
+
if #{to} || #{to}.respond_to?(:#{method}) # if client || client.respond_to?(:name)
|
|
150
|
+
#{to}.#{method}(#{definition}) # client.name(*args, &block)
|
|
151
|
+
end # end
|
|
152
|
+
end # end
|
|
153
|
+
EOS
|
|
154
|
+
else
|
|
155
|
+
exception = %(raise "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
|
|
156
|
+
|
|
157
|
+
module_eval(<<-EOS, file, line - 1)
|
|
158
|
+
def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
|
|
159
|
+
#{to}.#{method}(#{definition}) # client.name(*args, &block)
|
|
160
|
+
rescue NoMethodError # rescue NoMethodError
|
|
161
|
+
if #{to}.nil? # if client.nil?
|
|
162
|
+
#{exception} # # add helpful message to the exception
|
|
163
|
+
else # else
|
|
164
|
+
raise # raise
|
|
165
|
+
end # end
|
|
166
|
+
end # end
|
|
167
|
+
EOS
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module ModuleExt; end; module ModuleExt::Deprecation
|
|
2
|
+
require 'active_support/deprecation/method_wrappers'
|
|
3
|
+
|
|
4
|
+
refine Module do
|
|
5
|
+
# deprecate :foo
|
|
6
|
+
# deprecate bar: 'message'
|
|
7
|
+
# deprecate :foo, :bar, baz: 'warning!', qux: 'gone!'
|
|
8
|
+
#
|
|
9
|
+
# You can also use custom deprecator instance:
|
|
10
|
+
#
|
|
11
|
+
# deprecate :foo, deprecator: MyLib::Deprecator.new
|
|
12
|
+
# deprecate :foo, bar: "warning!", deprecator: MyLib::Deprecator.new
|
|
13
|
+
#
|
|
14
|
+
# \Custom deprecators must respond to <tt>deprecation_warning(deprecated_method_name, message, caller_backtrace)</tt>
|
|
15
|
+
# method where you can implement your custom warning behavior.
|
|
16
|
+
#
|
|
17
|
+
# class MyLib::Deprecator
|
|
18
|
+
# def deprecation_warning(deprecated_method_name, message, caller_backtrace)
|
|
19
|
+
# message = "#{method_name} is deprecated and will be removed from MyLibrary | #{message}"
|
|
20
|
+
# Kernel.warn message
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
def deprecate(*method_names)
|
|
24
|
+
ActiveSupport::Deprecation.deprecate_methods(self, *method_names)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module ModuleExt; end; module ModuleExt::Introspection
|
|
2
|
+
require 'active_support/inflector'
|
|
3
|
+
|
|
4
|
+
refine Module do
|
|
5
|
+
# Returns the name of the module containing this one.
|
|
6
|
+
#
|
|
7
|
+
# M::N.parent_name # => "M"
|
|
8
|
+
def parent_name
|
|
9
|
+
if defined? @parent_name
|
|
10
|
+
@parent_name
|
|
11
|
+
else
|
|
12
|
+
@parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Returns the module which contains this one according to its name.
|
|
17
|
+
#
|
|
18
|
+
# module M
|
|
19
|
+
# module N
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
# X = M::N
|
|
23
|
+
#
|
|
24
|
+
# M::N.parent # => M
|
|
25
|
+
# X.parent # => M
|
|
26
|
+
#
|
|
27
|
+
# The parent of top-level and anonymous modules is Object.
|
|
28
|
+
#
|
|
29
|
+
# M.parent # => Object
|
|
30
|
+
# Module.new.parent # => Object
|
|
31
|
+
def parent
|
|
32
|
+
parent_name ? ActiveSupport::Inflector.constantize(parent_name) : Object
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Returns all the parents of this module according to its name, ordered from
|
|
36
|
+
# nested outwards. The receiver is not contained within the result.
|
|
37
|
+
#
|
|
38
|
+
# module M
|
|
39
|
+
# module N
|
|
40
|
+
# end
|
|
41
|
+
# end
|
|
42
|
+
# X = M::N
|
|
43
|
+
#
|
|
44
|
+
# M.parents # => [Object]
|
|
45
|
+
# M::N.parents # => [M, Object]
|
|
46
|
+
# X.parents # => [M, Object]
|
|
47
|
+
def parents
|
|
48
|
+
parents = []
|
|
49
|
+
if parent_name
|
|
50
|
+
parts = parent_name.split('::')
|
|
51
|
+
until parts.empty?
|
|
52
|
+
parents << ActiveSupport::Inflector.constantize(parts * '::')
|
|
53
|
+
parts.pop
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
parents << Object unless parents.include? Object
|
|
57
|
+
parents
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def local_constants #:nodoc:
|
|
61
|
+
constants(false)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# *DEPRECATED*: Use +local_constants+ instead.
|
|
65
|
+
#
|
|
66
|
+
# Returns the names of the constants defined locally as strings.
|
|
67
|
+
#
|
|
68
|
+
# module M
|
|
69
|
+
# X = 1
|
|
70
|
+
# end
|
|
71
|
+
# M.local_constant_names # => ["X"]
|
|
72
|
+
#
|
|
73
|
+
# This method is useful for forward compatibility, since Ruby 1.8 returns
|
|
74
|
+
# constant names as strings, whereas 1.9 returns them as symbols.
|
|
75
|
+
def local_constant_names
|
|
76
|
+
ActiveSupport::Deprecation.warn 'Module#local_constant_names is deprecated, use Module#local_constants instead', caller
|
|
77
|
+
local_constants.map { |c| c.to_s }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module ModuleExt; end; module ModuleExt::QualifiedConst
|
|
2
|
+
require 'active_support/refinements/core_ext/string/inflections'
|
|
3
|
+
|
|
4
|
+
#--
|
|
5
|
+
# Allows code reuse in the methods below without polluting Module.
|
|
6
|
+
#++
|
|
7
|
+
module QualifiedConstUtils
|
|
8
|
+
def self.raise_if_absolute(path)
|
|
9
|
+
raise NameError.new("wrong constant name #$&") if path =~ /\A::[^:]+/
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.names(path)
|
|
13
|
+
path.split('::')
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Extends the API for constants to be able to deal with qualified names. Arguments
|
|
19
|
+
# are assumed to be relative to the receiver.
|
|
20
|
+
#
|
|
21
|
+
#--
|
|
22
|
+
# Qualified names are required to be relative because we are extending existing
|
|
23
|
+
# methods that expect constant names, ie, relative paths of length 1. For example,
|
|
24
|
+
# Object.const_get('::String') raises NameError and so does qualified_const_get.
|
|
25
|
+
#++
|
|
26
|
+
refine Module do
|
|
27
|
+
def qualified_const_defined?(path, search_parents=true)
|
|
28
|
+
QualifiedConstUtils.raise_if_absolute(path)
|
|
29
|
+
|
|
30
|
+
QualifiedConstUtils.names(path).inject(self) do |mod, name|
|
|
31
|
+
return unless mod.const_defined?(name, search_parents)
|
|
32
|
+
mod.const_get(name)
|
|
33
|
+
end
|
|
34
|
+
return true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def qualified_const_get(path)
|
|
38
|
+
QualifiedConstUtils.raise_if_absolute(path)
|
|
39
|
+
|
|
40
|
+
QualifiedConstUtils.names(path).inject(self) do |mod, name|
|
|
41
|
+
mod.const_get(name)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def qualified_const_set(path, value)
|
|
46
|
+
QualifiedConstUtils.raise_if_absolute(path)
|
|
47
|
+
|
|
48
|
+
const_name = path.demodulize
|
|
49
|
+
mod_name = path.deconstantize
|
|
50
|
+
mod = mod_name.empty? ? self : qualified_const_get(mod_name)
|
|
51
|
+
mod.const_set(const_name, value)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module ModuleExt; end; module ModuleExt::Reachable
|
|
2
|
+
require 'active_support/refinements/core_ext/module/anonymous'
|
|
3
|
+
require 'active_support/refinements/core_ext/string/inflections'
|
|
4
|
+
|
|
5
|
+
refine Module do
|
|
6
|
+
def reachable? #:nodoc:
|
|
7
|
+
!anonymous? && name.safe_constantize.equal?(self)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|