garcun 0.0.2
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/.gitattributes +17 -0
- data/.gitignore +197 -0
- data/.rspec +2 -0
- data/Gemfile +22 -0
- data/LICENSE +201 -0
- data/README.md +521 -0
- data/Rakefile +47 -0
- data/garcun.gemspec +83 -0
- data/lib/garcon.rb +290 -0
- data/lib/garcon/chef/chef_helpers.rb +343 -0
- data/lib/garcon/chef/coerce/coercer.rb +134 -0
- data/lib/garcon/chef/coerce/coercions/boolean_definitions.rb +34 -0
- data/lib/garcon/chef/coerce/coercions/date_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/date_time_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/fixnum_definitions.rb +34 -0
- data/lib/garcon/chef/coerce/coercions/float_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/hash_definitions.rb +29 -0
- data/lib/garcon/chef/coerce/coercions/integer_definitions.rb +31 -0
- data/lib/garcon/chef/coerce/coercions/string_definitions.rb +45 -0
- data/lib/garcon/chef/coerce/coercions/time_definitions.rb +32 -0
- data/lib/garcon/chef/handler/devreporter.rb +127 -0
- data/lib/garcon/chef/log.rb +64 -0
- data/lib/garcon/chef/node.rb +100 -0
- data/lib/garcon/chef/provider/civilize.rb +209 -0
- data/lib/garcon/chef/provider/development.rb +159 -0
- data/lib/garcon/chef/provider/download.rb +420 -0
- data/lib/garcon/chef/provider/house_keeping.rb +265 -0
- data/lib/garcon/chef/provider/node_cache.rb +31 -0
- data/lib/garcon/chef/provider/partial.rb +183 -0
- data/lib/garcon/chef/provider/recovery.rb +80 -0
- data/lib/garcon/chef/provider/zip_file.rb +271 -0
- data/lib/garcon/chef/resource/attribute.rb +52 -0
- data/lib/garcon/chef/resource/base_dsl.rb +174 -0
- data/lib/garcon/chef/resource/blender.rb +140 -0
- data/lib/garcon/chef/resource/lazy_eval.rb +66 -0
- data/lib/garcon/chef/resource/resource_name.rb +109 -0
- data/lib/garcon/chef/secret_bag.rb +204 -0
- data/lib/garcon/chef/validations.rb +76 -0
- data/lib/garcon/chef_inclusions.rb +151 -0
- data/lib/garcon/configuration.rb +138 -0
- data/lib/garcon/core_ext.rb +39 -0
- data/lib/garcon/core_ext/array.rb +27 -0
- data/lib/garcon/core_ext/binding.rb +64 -0
- data/lib/garcon/core_ext/boolean.rb +66 -0
- data/lib/garcon/core_ext/duration.rb +271 -0
- data/lib/garcon/core_ext/enumerable.rb +34 -0
- data/lib/garcon/core_ext/file.rb +127 -0
- data/lib/garcon/core_ext/filetest.rb +62 -0
- data/lib/garcon/core_ext/hash.rb +279 -0
- data/lib/garcon/core_ext/kernel.rb +159 -0
- data/lib/garcon/core_ext/lazy.rb +222 -0
- data/lib/garcon/core_ext/method_access.rb +243 -0
- data/lib/garcon/core_ext/module.rb +92 -0
- data/lib/garcon/core_ext/nil.rb +53 -0
- data/lib/garcon/core_ext/numeric.rb +44 -0
- data/lib/garcon/core_ext/object.rb +342 -0
- data/lib/garcon/core_ext/pathname.rb +152 -0
- data/lib/garcon/core_ext/process.rb +41 -0
- data/lib/garcon/core_ext/random.rb +497 -0
- data/lib/garcon/core_ext/string.rb +312 -0
- data/lib/garcon/core_ext/struct.rb +49 -0
- data/lib/garcon/core_ext/symbol.rb +170 -0
- data/lib/garcon/core_ext/time.rb +234 -0
- data/lib/garcon/exceptions.rb +101 -0
- data/lib/garcon/inflections.rb +237 -0
- data/lib/garcon/inflections/defaults.rb +79 -0
- data/lib/garcon/inflections/inflections.rb +182 -0
- data/lib/garcon/inflections/rules_collection.rb +37 -0
- data/lib/garcon/secret.rb +271 -0
- data/lib/garcon/stash/format.rb +114 -0
- data/lib/garcon/stash/journal.rb +226 -0
- data/lib/garcon/stash/queue.rb +83 -0
- data/lib/garcon/stash/serializer.rb +86 -0
- data/lib/garcon/stash/store.rb +435 -0
- data/lib/garcon/task.rb +31 -0
- data/lib/garcon/task/atomic.rb +151 -0
- data/lib/garcon/task/atomic_boolean.rb +127 -0
- data/lib/garcon/task/condition.rb +99 -0
- data/lib/garcon/task/copy_on_notify_observer_set.rb +154 -0
- data/lib/garcon/task/copy_on_write_observer_set.rb +153 -0
- data/lib/garcon/task/count_down_latch.rb +92 -0
- data/lib/garcon/task/delay.rb +196 -0
- data/lib/garcon/task/dereferenceable.rb +144 -0
- data/lib/garcon/task/event.rb +119 -0
- data/lib/garcon/task/executor.rb +275 -0
- data/lib/garcon/task/executor_options.rb +59 -0
- data/lib/garcon/task/future.rb +107 -0
- data/lib/garcon/task/immediate_executor.rb +84 -0
- data/lib/garcon/task/ivar.rb +171 -0
- data/lib/garcon/task/lazy_reference.rb +74 -0
- data/lib/garcon/task/monotonic_time.rb +69 -0
- data/lib/garcon/task/obligation.rb +256 -0
- data/lib/garcon/task/observable.rb +101 -0
- data/lib/garcon/task/priority_queue.rb +234 -0
- data/lib/garcon/task/processor_count.rb +128 -0
- data/lib/garcon/task/read_write_lock.rb +304 -0
- data/lib/garcon/task/safe_task_executor.rb +58 -0
- data/lib/garcon/task/single_thread_executor.rb +97 -0
- data/lib/garcon/task/thread_pool/cached.rb +71 -0
- data/lib/garcon/task/thread_pool/executor.rb +294 -0
- data/lib/garcon/task/thread_pool/fixed.rb +61 -0
- data/lib/garcon/task/thread_pool/worker.rb +90 -0
- data/lib/garcon/task/timer.rb +44 -0
- data/lib/garcon/task/timer_set.rb +194 -0
- data/lib/garcon/task/timer_task.rb +377 -0
- data/lib/garcon/task/waitable_list.rb +58 -0
- data/lib/garcon/utility/ansi.rb +199 -0
- data/lib/garcon/utility/at_random.rb +77 -0
- data/lib/garcon/utility/crypto.rb +292 -0
- data/lib/garcon/utility/equalizer.rb +146 -0
- data/lib/garcon/utility/faker/extensions/array.rb +22 -0
- data/lib/garcon/utility/faker/extensions/symbol.rb +9 -0
- data/lib/garcon/utility/faker/faker.rb +164 -0
- data/lib/garcon/utility/faker/faker/company.rb +17 -0
- data/lib/garcon/utility/faker/faker/hacker.rb +30 -0
- data/lib/garcon/utility/faker/faker/version.rb +3 -0
- data/lib/garcon/utility/faker/locales/en-US.yml +83 -0
- data/lib/garcon/utility/faker/locales/en.yml +21 -0
- data/lib/garcon/utility/file_helper.rb +170 -0
- data/lib/garcon/utility/hookers.rb +178 -0
- data/lib/garcon/utility/interpolation.rb +90 -0
- data/lib/garcon/utility/memstash.rb +364 -0
- data/lib/garcon/utility/misc.rb +54 -0
- data/lib/garcon/utility/msg_from_god.rb +62 -0
- data/lib/garcon/utility/retry.rb +238 -0
- data/lib/garcon/utility/timeout.rb +58 -0
- data/lib/garcon/utility/uber/builder.rb +91 -0
- data/lib/garcon/utility/uber/callable.rb +7 -0
- data/lib/garcon/utility/uber/delegates.rb +13 -0
- data/lib/garcon/utility/uber/inheritable_attr.rb +37 -0
- data/lib/garcon/utility/uber/options.rb +101 -0
- data/lib/garcon/utility/uber/uber_version.rb +3 -0
- data/lib/garcon/utility/uber/version.rb +33 -0
- data/lib/garcon/utility/url_helper.rb +100 -0
- data/lib/garcon/utils.rb +29 -0
- data/lib/garcon/version.rb +62 -0
- data/lib/garcun.rb +24 -0
- metadata +680 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
class Module
|
|
21
|
+
|
|
22
|
+
# Create an instance of Object and extend it with +self+.
|
|
23
|
+
#
|
|
24
|
+
# mod = Module.new do
|
|
25
|
+
# def foo; "foo"; end
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
28
|
+
# obj = mod.to_obj
|
|
29
|
+
#
|
|
30
|
+
# obj.foo #=> "foo"
|
|
31
|
+
#
|
|
32
|
+
def to_obj
|
|
33
|
+
o = Object.new
|
|
34
|
+
o.extend self
|
|
35
|
+
o
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Creates a new method wrapping the previous of the same name.
|
|
39
|
+
# Reference to the old method is passed into the new definition
|
|
40
|
+
# block as the first parameter.
|
|
41
|
+
#
|
|
42
|
+
# class WrapExample
|
|
43
|
+
# def foo
|
|
44
|
+
# "foo"
|
|
45
|
+
# end
|
|
46
|
+
#
|
|
47
|
+
# wrap_method(:foo) do |old_meth, *args|
|
|
48
|
+
# old_meth.call + '!'
|
|
49
|
+
# end
|
|
50
|
+
# end
|
|
51
|
+
#
|
|
52
|
+
# example = WrapExample.new
|
|
53
|
+
# example.foo #=> 'foo!'
|
|
54
|
+
#
|
|
55
|
+
# Keep in mind that this cannot be used to wrap methods
|
|
56
|
+
# that take a block.
|
|
57
|
+
#
|
|
58
|
+
def wrap_method( sym, &blk )
|
|
59
|
+
old = instance_method(sym)
|
|
60
|
+
define_method(sym) { |*args| blk.call(old.bind(self), *args) }
|
|
61
|
+
end
|
|
62
|
+
alias_method :wrap, :wrap_method
|
|
63
|
+
|
|
64
|
+
unless method_defined?(:set)
|
|
65
|
+
# Sets an option to the given value. If the value is a proc,
|
|
66
|
+
# the proc will be called every time the option is accessed.
|
|
67
|
+
#
|
|
68
|
+
def set(option, value=self, &block)
|
|
69
|
+
raise ArgumentError if block && value != self
|
|
70
|
+
value = block if block
|
|
71
|
+
if value.kind_of?(Proc)
|
|
72
|
+
if value.arity == 1
|
|
73
|
+
yield self
|
|
74
|
+
else
|
|
75
|
+
(class << self; self; end).module_eval do
|
|
76
|
+
define_method(option, &value)
|
|
77
|
+
define_method("#{option}?"){ !!__send__(option) }
|
|
78
|
+
define_method("#{option}="){ |val| set(option, Proc.new{val}) }
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
elsif value == self
|
|
82
|
+
option.each{ |k,v| set(k, v) }
|
|
83
|
+
elsif respond_to?("#{option}=")
|
|
84
|
+
__send__("#{option}=", value)
|
|
85
|
+
else
|
|
86
|
+
set(option, Proc.new{value})
|
|
87
|
+
end
|
|
88
|
+
self
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
# Add #blank? method to NilClass class.
|
|
21
|
+
class NilClass
|
|
22
|
+
# Nil is always blank
|
|
23
|
+
#
|
|
24
|
+
# @example
|
|
25
|
+
# nil.blank? # => true
|
|
26
|
+
#
|
|
27
|
+
# @return [TrueClass]
|
|
28
|
+
#
|
|
29
|
+
# @api public
|
|
30
|
+
def blank?
|
|
31
|
+
true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Calling `try` on `nil` always returns `nil`. It becomes especially helpful
|
|
35
|
+
# when navigating through associations that may return `nil`.
|
|
36
|
+
#
|
|
37
|
+
def try(*args)
|
|
38
|
+
nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def try!(*args)
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Since NilClass is immutable it cannot be duplicated.
|
|
46
|
+
# For this reason #try_dup returns +self+.
|
|
47
|
+
#
|
|
48
|
+
# nil.dup! #=> nil
|
|
49
|
+
#
|
|
50
|
+
def dup! ; self ; end
|
|
51
|
+
def dup? ; false ; end
|
|
52
|
+
def clone? ; false ; end
|
|
53
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
# Add #blank? method to Numeric class.
|
|
21
|
+
class Numeric
|
|
22
|
+
# Numerics are never blank
|
|
23
|
+
#
|
|
24
|
+
# @example
|
|
25
|
+
# 0.blank? # => false
|
|
26
|
+
# 1.blank? # => false
|
|
27
|
+
# 6.54321.blank? # => false
|
|
28
|
+
#
|
|
29
|
+
# @return [FalseClass]
|
|
30
|
+
#
|
|
31
|
+
# @api public
|
|
32
|
+
def blank?
|
|
33
|
+
false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Since Numeric is immutable it cannot be duplicated.
|
|
37
|
+
# For this reason #try_dup returns +self+.
|
|
38
|
+
#
|
|
39
|
+
# 1.dup! #=> 1
|
|
40
|
+
#
|
|
41
|
+
def dup! ; self ; end
|
|
42
|
+
def dup? ; false ; end
|
|
43
|
+
def clone? ; false ; end
|
|
44
|
+
end
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Add #blank?, #present?, #try and #try! methods to Object class.
|
|
22
|
+
class Object
|
|
23
|
+
|
|
24
|
+
# Returns true if the object is nil or empty (if applicable)
|
|
25
|
+
#
|
|
26
|
+
# @example
|
|
27
|
+
# [].blank? # => true
|
|
28
|
+
# [1].blank? # => false
|
|
29
|
+
# [nil].blank? # => false
|
|
30
|
+
#
|
|
31
|
+
# @return [Boolean]
|
|
32
|
+
#
|
|
33
|
+
def blank?
|
|
34
|
+
nil? || (respond_to?(:empty?) && empty?)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Returns true if the object is NOT nil or empty
|
|
38
|
+
#
|
|
39
|
+
# @example
|
|
40
|
+
# [].present? # => false
|
|
41
|
+
# [1].present? # => true
|
|
42
|
+
# [nil].present? # => true
|
|
43
|
+
#
|
|
44
|
+
# @return [Boolean]
|
|
45
|
+
#
|
|
46
|
+
def present?
|
|
47
|
+
!blank?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Invokes the public method whose name goes as first argument just like
|
|
51
|
+
# `public_send` does, except that if the receiver does not respond to it the
|
|
52
|
+
# call returns `nil` rather than raising an exception.
|
|
53
|
+
#
|
|
54
|
+
# @note
|
|
55
|
+
# `try` is defined on `Object`. Therefore, it won't work with instances
|
|
56
|
+
# of classes that do not have `Object` among their ancestors, like direct
|
|
57
|
+
# subclasses of `BasicObject`.
|
|
58
|
+
#
|
|
59
|
+
# @param [String] object
|
|
60
|
+
#
|
|
61
|
+
# @param [Symbol] method
|
|
62
|
+
#
|
|
63
|
+
# @return [Object]
|
|
64
|
+
#
|
|
65
|
+
def try(*a, &b)
|
|
66
|
+
try!(*a, &b) if a.empty? || respond_to?(a.first)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Same as #try, but will raise a NoMethodError exception if the receiver is
|
|
70
|
+
# not `nil` and does not implement the tried method.
|
|
71
|
+
#
|
|
72
|
+
# @raise NoMethodError
|
|
73
|
+
# If the receiver is not `nil` and does not implement the tried method.
|
|
74
|
+
#
|
|
75
|
+
# @return [Object]
|
|
76
|
+
#
|
|
77
|
+
def try!(*a, &b)
|
|
78
|
+
if a.empty? && block_given?
|
|
79
|
+
if b.arity.zero?
|
|
80
|
+
instance_eval(&b)
|
|
81
|
+
else
|
|
82
|
+
yield self
|
|
83
|
+
end
|
|
84
|
+
else
|
|
85
|
+
public_send(*a, &b)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# If receiver is callable, calls it and returns result. If not, just returns
|
|
90
|
+
# receiver itself.
|
|
91
|
+
#
|
|
92
|
+
# @return [Object]
|
|
93
|
+
#
|
|
94
|
+
def try_call(*args)
|
|
95
|
+
if self.respond_to?(:call)
|
|
96
|
+
self.call(*args)
|
|
97
|
+
else
|
|
98
|
+
self
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# An identity method that provides access to an object's 'self'.
|
|
103
|
+
#
|
|
104
|
+
# Example
|
|
105
|
+
# [1,2,3,4,5,1,2,2,3].group_by(&:itself)
|
|
106
|
+
# #=> {1=>[1, 1], 2=>[2, 2, 2], 3=>[3, 3], 4=>[4], 5=>[5]}
|
|
107
|
+
#
|
|
108
|
+
def itself
|
|
109
|
+
self
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Override this in a child class if it cannot be dup'ed.
|
|
113
|
+
#
|
|
114
|
+
# obj1 = Object.new
|
|
115
|
+
# obj2 = obj1.dup!
|
|
116
|
+
# obj2.equal?(obj1) #=> false
|
|
117
|
+
#
|
|
118
|
+
# @return [Object]
|
|
119
|
+
#
|
|
120
|
+
def dup!
|
|
121
|
+
dup
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Alternative name for #dup!
|
|
125
|
+
#
|
|
126
|
+
# @return [Object]
|
|
127
|
+
#
|
|
128
|
+
def try_dup
|
|
129
|
+
dup!
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Can you safely call #dup on this object?
|
|
133
|
+
#
|
|
134
|
+
# Returns `false` for `nil`, `false`, `true`, symbols, and numbers;
|
|
135
|
+
# `true` otherwise.
|
|
136
|
+
#
|
|
137
|
+
# @return [Object]
|
|
138
|
+
#
|
|
139
|
+
def dup? ; true ; end
|
|
140
|
+
def clone? ; true ; end
|
|
141
|
+
|
|
142
|
+
# Extracts the singleton class, so that metaprogramming can be done on it.
|
|
143
|
+
#
|
|
144
|
+
# @example [Setup]
|
|
145
|
+
# class MyString < String; end
|
|
146
|
+
#
|
|
147
|
+
# MyString.instance_eval do
|
|
148
|
+
# define_method :foo do
|
|
149
|
+
# puts self
|
|
150
|
+
# end
|
|
151
|
+
# end
|
|
152
|
+
#
|
|
153
|
+
# MyString.meta_class.instance_eval do
|
|
154
|
+
# define_method :bar do
|
|
155
|
+
# puts self
|
|
156
|
+
# end
|
|
157
|
+
# end
|
|
158
|
+
#
|
|
159
|
+
# def String.add_meta_var(var)
|
|
160
|
+
# self.meta_class.instance_eval do
|
|
161
|
+
# define_method var do
|
|
162
|
+
# puts "HELLO"
|
|
163
|
+
# end
|
|
164
|
+
# end
|
|
165
|
+
# end
|
|
166
|
+
#
|
|
167
|
+
# @example
|
|
168
|
+
# MyString.new("Hello").foo # => "Hello"
|
|
169
|
+
#
|
|
170
|
+
# @example
|
|
171
|
+
# MyString.new("Hello").bar
|
|
172
|
+
# # => NoMethodError: undefined method `bar' for "Hello":MyString
|
|
173
|
+
#
|
|
174
|
+
# @example
|
|
175
|
+
# MyString.foo
|
|
176
|
+
# # => NoMethodError: undefined method `foo' for MyString:Class
|
|
177
|
+
#
|
|
178
|
+
# @example
|
|
179
|
+
# MyString.bar
|
|
180
|
+
# # => MyString
|
|
181
|
+
#
|
|
182
|
+
# @example
|
|
183
|
+
# String.bar
|
|
184
|
+
# # => NoMethodError: undefined method `bar' for String:Class
|
|
185
|
+
#
|
|
186
|
+
# @example
|
|
187
|
+
# MyString.add_meta_var(:x)
|
|
188
|
+
# MyString.x # => HELLO
|
|
189
|
+
#
|
|
190
|
+
# @details [Description of Examples]
|
|
191
|
+
# As you can see, using #meta_class allows you to execute code (and here,
|
|
192
|
+
# define a method) on the metaclass itself. It also allows you to define
|
|
193
|
+
# class methods that can be run on subclasses, and then be able to execute
|
|
194
|
+
# code on the metaclass of the subclass (here MyString).
|
|
195
|
+
#
|
|
196
|
+
# In this case, we were able to define a class method (add_meta_var) on
|
|
197
|
+
# String that was executable by the MyString subclass. It was then able to
|
|
198
|
+
# define a method on the subclass by adding it to the MyString metaclass.
|
|
199
|
+
#
|
|
200
|
+
# @return [Class]
|
|
201
|
+
# The meta class.
|
|
202
|
+
#
|
|
203
|
+
def meta_class() class << self; self end end
|
|
204
|
+
|
|
205
|
+
# @param [String] name
|
|
206
|
+
# The name of the constant to get, e.g. "Garcon::Check".
|
|
207
|
+
#
|
|
208
|
+
# @return [Object]
|
|
209
|
+
# The constant corresponding to the name.
|
|
210
|
+
#
|
|
211
|
+
def full_const_get(name)
|
|
212
|
+
list = name.split('::')
|
|
213
|
+
list.shift if list.first.blank?
|
|
214
|
+
obj = self
|
|
215
|
+
list.each do |x|
|
|
216
|
+
obj = obj.const_defined?(x) ? obj.const_get(x) : obj.const_missing(x)
|
|
217
|
+
end
|
|
218
|
+
obj
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# @param [String] name
|
|
222
|
+
# The name of the constant to get, e.g. "Garcon::Check".
|
|
223
|
+
#
|
|
224
|
+
# @param [Object] value
|
|
225
|
+
# The value to assign to the constant.
|
|
226
|
+
#
|
|
227
|
+
# @return [Object]
|
|
228
|
+
# The constant corresponding to the name.
|
|
229
|
+
#
|
|
230
|
+
def full_const_set(name, value)
|
|
231
|
+
list = name.split('::')
|
|
232
|
+
toplevel = list.first.blank?
|
|
233
|
+
list.shift if toplevel
|
|
234
|
+
last = list.pop
|
|
235
|
+
obj = list.empty? ? Object : Object.full_const_get(list.join('::'))
|
|
236
|
+
obj.const_set(last, value) if obj && !obj.const_defined?(last)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Defines module from a string name (e.g. Foo::Bar::Baz). If module already
|
|
240
|
+
# exists, no exception raised.
|
|
241
|
+
#
|
|
242
|
+
# @param [String] name
|
|
243
|
+
# The name of the full module name to make
|
|
244
|
+
#
|
|
245
|
+
# @return [nil]
|
|
246
|
+
#
|
|
247
|
+
def make_module(string)
|
|
248
|
+
current_module = self
|
|
249
|
+
string.split('::').each do |part|
|
|
250
|
+
current_module = if current_module.const_defined?(part)
|
|
251
|
+
current_module.const_get(part)
|
|
252
|
+
else
|
|
253
|
+
current_module.const_set(part, Module.new)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
current_module
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# @param [Symbol, Class, Array] duck
|
|
260
|
+
# The thing to compare the object to.
|
|
261
|
+
#
|
|
262
|
+
# @note
|
|
263
|
+
# The behavior of the method depends on the type of duck as follows:
|
|
264
|
+
# Symbol:: Check whether the object respond_to?(duck).
|
|
265
|
+
# Class:: Check whether the object is_a?(duck).
|
|
266
|
+
# Array:: Check whether the object quacks_like? at least one of the
|
|
267
|
+
# options in the array.
|
|
268
|
+
#
|
|
269
|
+
# @return [Boolean]
|
|
270
|
+
# True if the object quacks like a duck.
|
|
271
|
+
#
|
|
272
|
+
def quacks_like?(duck)
|
|
273
|
+
case duck
|
|
274
|
+
when Symbol
|
|
275
|
+
self.respond_to?(duck)
|
|
276
|
+
when Class
|
|
277
|
+
self.is_a?(duck)
|
|
278
|
+
when Array
|
|
279
|
+
duck.any? { |d| self.quacks_like?(d) }
|
|
280
|
+
else
|
|
281
|
+
false
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# @example 1.in?([1,2,3]) # => true
|
|
286
|
+
#
|
|
287
|
+
# @example 1.in?(1,2,3) # => true
|
|
288
|
+
#
|
|
289
|
+
# @param [#include?] arrayish
|
|
290
|
+
# Container to check, to see if it includes the object.
|
|
291
|
+
#
|
|
292
|
+
# @param [Array] *more
|
|
293
|
+
# additional args, will be flattened into arrayish
|
|
294
|
+
#
|
|
295
|
+
# @return [Boolean]
|
|
296
|
+
# True if the object is included in arrayish (+ more)
|
|
297
|
+
#
|
|
298
|
+
def in?(arrayish, *more)
|
|
299
|
+
arrayish = more.unshift(arrayish) unless more.empty?
|
|
300
|
+
arrayish.include?(self)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Get or set state of object. You can think of #object_state as an in-code
|
|
304
|
+
# form of marshalling.
|
|
305
|
+
#
|
|
306
|
+
# class StateExample
|
|
307
|
+
# attr_reader :a, :b
|
|
308
|
+
# def initialize(a,b)
|
|
309
|
+
# @a, @b = a, b
|
|
310
|
+
# end
|
|
311
|
+
# end
|
|
312
|
+
#
|
|
313
|
+
# obj = StateExample.new(1,2)
|
|
314
|
+
# obj.a #=> 1
|
|
315
|
+
# obj.b #=> 2
|
|
316
|
+
#
|
|
317
|
+
# obj.object_state #=> {:a=>1, :b=>2}
|
|
318
|
+
#
|
|
319
|
+
# obj.object_state(:a=>3, :b=>4)
|
|
320
|
+
# obj.a #=> 3
|
|
321
|
+
# obj.b #=> 4
|
|
322
|
+
#
|
|
323
|
+
# For most object's this is essentially the same as `instance.to_h`.
|
|
324
|
+
# But for data structures like Array and Hash it returns a snapshot of their
|
|
325
|
+
# contents, not the state of their instance variables.
|
|
326
|
+
#
|
|
327
|
+
def object_state(data = nil)
|
|
328
|
+
if data
|
|
329
|
+
instance_variables.each do |iv|
|
|
330
|
+
name = iv.to_s.sub(/^[@]/, '').to_sym
|
|
331
|
+
instance_variable_set(iv, data[name])
|
|
332
|
+
end
|
|
333
|
+
else
|
|
334
|
+
data = {}
|
|
335
|
+
instance_variables.each do |iv|
|
|
336
|
+
name = iv.to_s.sub(/^[@]/, '').to_sym
|
|
337
|
+
data[name] = instance_variable_get(iv)
|
|
338
|
+
end
|
|
339
|
+
data
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
end
|