rake-commander 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +8 -0
- data/.rubocop.yml +12 -8
- data/CHANGELOG.md +69 -4
- data/LICENSE +21 -0
- data/README.md +94 -2
- data/Rakefile +11 -13
- data/examples/01_basic_example.rb +28 -0
- data/examples/02_a_chainer_example.rb +66 -0
- data/examples/02_a_chainer_options_set.rb +8 -0
- data/examples/02_b_chained_example.rb +13 -0
- data/examples/03_a_chainer_plus_example.rb +34 -0
- data/examples/03_b_chained_plus_example.rb +17 -0
- data/examples/Examples.rake +7 -0
- data/examples/README.md +79 -0
- data/examples/libs/shell_helpers.rb +81 -0
- data/lib/rake-commander/base/class_auto_loader.rb +45 -7
- data/lib/rake-commander/base/class_helpers.rb +16 -61
- data/lib/rake-commander/base/class_inheritable.rb +122 -0
- data/lib/rake-commander/base/custom_error.rb +52 -0
- data/lib/rake-commander/base/object_helpers.rb +42 -0
- data/lib/rake-commander/base.rb +16 -2
- data/lib/rake-commander/option.rb +115 -25
- data/lib/rake-commander/options/arguments.rb +206 -94
- data/lib/rake-commander/options/description.rb +17 -0
- data/lib/rake-commander/options/error/base.rb +86 -0
- data/lib/rake-commander/options/error/handling.rb +106 -0
- data/lib/rake-commander/options/error/invalid_argument.rb +21 -0
- data/lib/rake-commander/options/error/invalid_option.rb +9 -0
- data/lib/rake-commander/options/error/missing_argument.rb +10 -0
- data/lib/rake-commander/options/error/missing_option.rb +48 -0
- data/lib/rake-commander/options/error/unknown_argument.rb +32 -0
- data/lib/rake-commander/options/error.rb +75 -10
- data/lib/rake-commander/options/name.rb +67 -23
- data/lib/rake-commander/options/result.rb +107 -0
- data/lib/rake-commander/options/set.rb +7 -1
- data/lib/rake-commander/options.rb +175 -98
- data/lib/rake-commander/patcher/README.md +79 -0
- data/lib/rake-commander/patcher/application/run_method.rb +46 -0
- data/lib/rake-commander/patcher/application/top_level_method.rb +74 -0
- data/lib/rake-commander/patcher/application.rb +16 -0
- data/lib/rake-commander/patcher/base.rb +45 -0
- data/lib/rake-commander/patcher/debug.rb +32 -0
- data/lib/rake-commander/patcher/helpers.rb +44 -0
- data/lib/rake-commander/patcher.rb +26 -0
- data/lib/rake-commander/rake_context/wrapper.rb +2 -0
- data/lib/rake-commander/rake_task.rb +49 -54
- data/lib/rake-commander/version.rb +1 -1
- data/lib/rake-commander.rb +4 -0
- data/rake-commander.gemspec +4 -1
- metadata +74 -6
- data/examples/basic.rb +0 -30
- data/lib/rake-commander/options/error_rely.rb +0 -58
@@ -0,0 +1,81 @@
|
|
1
|
+
module Examples
|
2
|
+
module Libs
|
3
|
+
module ShellHelpers
|
4
|
+
SHELL_METHODS = %I[system back_quotes x spawn exec fork_exec pipe].freeze
|
5
|
+
|
6
|
+
# https://stackoverflow.com/a/37329716/4352306
|
7
|
+
def shell(cmd, method: :system)
|
8
|
+
method = method.to_sym
|
9
|
+
case method
|
10
|
+
when :system
|
11
|
+
success = system(cmd)
|
12
|
+
puts "* #{success ? "Succeded in" : "Failed to"} running '#{cmd}'"
|
13
|
+
when :back_quotes, :x
|
14
|
+
result = `#{cmd}`
|
15
|
+
puts result
|
16
|
+
#%x(#{cmd})
|
17
|
+
when :spawn # like Kernel.system but with no wait
|
18
|
+
pid = Process.spawn(cmd)
|
19
|
+
puts "* new child process (pid: #{pid}). Will wait..."
|
20
|
+
Process.wait(pid)
|
21
|
+
puts "* child process finished (pid: #{pid})"
|
22
|
+
when :exec
|
23
|
+
exec cmd
|
24
|
+
# Flow does not reach here
|
25
|
+
when :fork_exec
|
26
|
+
for_exec(cmd)
|
27
|
+
when :pipe # I/O of new process
|
28
|
+
pipe(cmd)
|
29
|
+
else
|
30
|
+
raise "* unknown shell method '#{method}'"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def fork_exec(cmd)
|
35
|
+
pid = fork do
|
36
|
+
shell(cmd, method: :exec)
|
37
|
+
end
|
38
|
+
puts "* new child process (pid: #{pid})"
|
39
|
+
rescue NotImplementedError => e
|
40
|
+
puts e
|
41
|
+
puts "Redirecting to 'spawn'"
|
42
|
+
shell(cmd, method: :spawn)
|
43
|
+
end
|
44
|
+
|
45
|
+
def pipe(cmd)
|
46
|
+
IO.popen(host_shell_command, 'r+') do |pipe|
|
47
|
+
puts "* new child process (pid: #{pipe.pid})"
|
48
|
+
prompt = pipe_prompt(pipe)
|
49
|
+
pipe.puts cmd
|
50
|
+
pipe.close_write # prevent `gets` to get stuck
|
51
|
+
lines = pipe.readlines
|
52
|
+
if index = lines.index {|ln| ln.include?(cmd)}
|
53
|
+
lines = lines[index+1..]
|
54
|
+
end
|
55
|
+
lines.reject! {|ln| ln.start_with?(prompt)}
|
56
|
+
lines = lines.map {|ln| ">> (pid: #{pipe.pid}) #{ln}"}
|
57
|
+
puts lines
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Changes the commandline prompt, so we can discard those.
|
62
|
+
def pipe_prompt(pipe, prompt: ':>$ ')
|
63
|
+
if Gem::Platform.local.os == "mingw32"
|
64
|
+
pipe.puts "function prompt {\"#{prompt}\"}"
|
65
|
+
else
|
66
|
+
pipe.puts "PS1=\"#{prompt}\""
|
67
|
+
end
|
68
|
+
prompt
|
69
|
+
end
|
70
|
+
|
71
|
+
# Command to open a new shell for `pipe`
|
72
|
+
def host_shell_command
|
73
|
+
if Gem::Platform.local.os == "mingw32"
|
74
|
+
"powershell -noprofile -noninteractive"
|
75
|
+
else
|
76
|
+
'sh'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -25,17 +25,25 @@ class RakeCommander
|
|
25
25
|
end
|
26
26
|
|
27
27
|
# To restrict which namespaces it is allowed to load from
|
28
|
+
# @note this deletes from the `:ignore` namespaces
|
28
29
|
def autoload_namespace(*namespaces)
|
29
30
|
_autoload_namespace(:include, *namespaces)
|
30
31
|
end
|
31
32
|
|
32
33
|
# To ignore certain namespaces this class should not autoload from
|
34
|
+
# @note this deletes from the `:include` namespaces
|
33
35
|
def autoload_namespace_ignore(*namespaces)
|
34
36
|
_autoload_namespace(:ignore, *namespaces)
|
35
37
|
end
|
36
38
|
|
39
|
+
# Applies a change to the `autoloaded_namespaces`
|
37
40
|
def _autoload_namespace(type, *namespaces)
|
38
|
-
autoloaded_namespaces(type).
|
41
|
+
autoloaded_namespaces(type).tap do |target|
|
42
|
+
next if namespaces.empty?
|
43
|
+
other_type = type == :include ? :ignore : :include
|
44
|
+
namespaces.each {|nm_sp| autoloaded_namespace(other_type).delete(nm_sp)}
|
45
|
+
target.concat(namespaces)
|
46
|
+
end
|
39
47
|
end
|
40
48
|
|
41
49
|
# @param constant [Class, String] a class or namespace we want to check auto-load entitlement thereof.
|
@@ -61,14 +69,36 @@ class RakeCommander
|
|
61
69
|
@autoloaded_children ||= []
|
62
70
|
end
|
63
71
|
|
72
|
+
# Keep track on actual children that have been ignored by `autoload_namespace_ignore`.
|
73
|
+
def ignored_children
|
74
|
+
@ignored_children ||= []
|
75
|
+
end
|
76
|
+
|
77
|
+
# Allows to reload
|
78
|
+
# @note it may be handy some times.
|
79
|
+
def clear_autoloaded_children
|
80
|
+
forget_class!(*autoloaded_children, *ignored_children)
|
81
|
+
@ignored_children = []
|
82
|
+
@autoloaded_children = []
|
83
|
+
end
|
84
|
+
|
85
|
+
# Prevents already excluded children to enter into the loop again.
|
86
|
+
def excluded_children
|
87
|
+
@excluded_children ||= []
|
88
|
+
end
|
89
|
+
|
64
90
|
# Children classes of `autoloader_class` that have not been created an instance of.
|
65
91
|
def unloaded_children
|
66
92
|
return [] unless autoloaded_class
|
67
93
|
new_detected = new_classes
|
68
94
|
known_class!(*new_detected)
|
69
95
|
descendants(parent_class: autoloaded_class, scope: new_detected).select do |child_class|
|
70
|
-
!autoloaded_children.include?(child_class) &&
|
71
|
-
|
96
|
+
!autoloaded_children.include?(child_class) && \
|
97
|
+
!excluded_children.include?(child_class) && \
|
98
|
+
autoload_class?(child_class).tap do |ignored|
|
99
|
+
ignored_children.push(child_class) if ignored
|
100
|
+
end
|
101
|
+
end
|
72
102
|
end
|
73
103
|
|
74
104
|
# It loads/creates a new instance of children classes pending to be loaded.
|
@@ -79,14 +109,15 @@ class RakeCommander
|
|
79
109
|
return false if pending_children.empty?
|
80
110
|
@loading_children = true
|
81
111
|
pending_children.each do |klass|
|
82
|
-
|
112
|
+
exclude = false
|
113
|
+
child = object ? klass.new(object) : klass.new
|
83
114
|
yield(child) if block_given?
|
84
|
-
|
85
115
|
rescue TypeError
|
86
116
|
# Can't create from this class (must be the singleton class)
|
87
|
-
|
117
|
+
exclude = true
|
118
|
+
excluded_children.push(klass)
|
88
119
|
ensure
|
89
|
-
autoloaded_children.push(klass)
|
120
|
+
autoloaded_children.push(klass) unless exclude
|
90
121
|
end
|
91
122
|
@loading_children = false
|
92
123
|
true
|
@@ -101,6 +132,13 @@ class RakeCommander
|
|
101
132
|
# Add to known namespaces
|
102
133
|
def known_class!(*classes)
|
103
134
|
known_classes.concat(classes)
|
135
|
+
self
|
136
|
+
end
|
137
|
+
|
138
|
+
# Forget namespaces
|
139
|
+
def forget_class!(*classes)
|
140
|
+
@known_classes = known_classes - classes
|
141
|
+
self
|
104
142
|
end
|
105
143
|
|
106
144
|
# List all new namespaces
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class RakeCommander
|
2
2
|
module Base
|
3
3
|
module ClassHelpers
|
4
|
-
NOT_USED =
|
4
|
+
NOT_USED = :not_used!
|
5
5
|
|
6
6
|
# Helper to determine if a paramter has been used
|
7
7
|
# @note to effectivelly use this helper, you should initialize your target
|
@@ -65,15 +65,6 @@ class RakeCommander
|
|
65
65
|
end.join("")
|
66
66
|
end
|
67
67
|
|
68
|
-
# Helper to create an instance variable `name`
|
69
|
-
# @param [String, Symbol] the name of the variable
|
70
|
-
# @reutrn [String] the name of the created instance variable
|
71
|
-
def instance_variable_name(name)
|
72
|
-
str = name.to_s
|
73
|
-
str = "@#{str}" unless str.start_with?("@")
|
74
|
-
str
|
75
|
-
end
|
76
|
-
|
77
68
|
# If the class for `name` exists, it returns it. Otherwise it generates it.
|
78
69
|
# @param name [String, Symbol] the name of the new class
|
79
70
|
# @param inherits [Class] the parent class to _inherit_ from
|
@@ -95,6 +86,16 @@ class RakeCommander
|
|
95
86
|
end
|
96
87
|
end
|
97
88
|
|
89
|
+
# @param klasses [Arrary<Class>] the classes to sort.
|
90
|
+
# @return [Arrary<Class>] the classes in hierarchy order.
|
91
|
+
def sort_classes(*klasses)
|
92
|
+
klasses.sort do |k_1, k_2|
|
93
|
+
next -1 if k_2 < k_1
|
94
|
+
next 1 if k_1 < k_2
|
95
|
+
0
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
98
99
|
# Finds all child classes of the current class.
|
99
100
|
# @param parent_class [Class] the parent class we want to find children of.
|
100
101
|
# @param direct [Boolean] it will only include direct child classes.
|
@@ -103,18 +104,11 @@ class RakeCommander
|
|
103
104
|
def descendants(parent_class: self, direct: false, scope: nil)
|
104
105
|
scope ||= ObjectSpace.each_object(::Class)
|
105
106
|
return [] if scope.empty?
|
106
|
-
scope.select
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
0
|
112
|
-
end.tap do |siblings|
|
113
|
-
if direct
|
114
|
-
siblings.reject! do |si|
|
115
|
-
siblings.any? {|s| si < s}
|
116
|
-
end
|
117
|
-
end
|
107
|
+
siblings = scope.select {|klass| klass < parent_class}
|
108
|
+
siblings = sort_classes(*siblings)
|
109
|
+
return siblings unless direct
|
110
|
+
siblings.reject! do |si|
|
111
|
+
siblings.any? {|s| si < s}
|
118
112
|
end
|
119
113
|
end
|
120
114
|
|
@@ -124,45 +118,6 @@ class RakeCommander
|
|
124
118
|
def descendants?(parent_class: self, direct: false)
|
125
119
|
!descendants(parent_class: parent_class, direct: direct).empty?
|
126
120
|
end
|
127
|
-
|
128
|
-
# Keeps track on class instance variables that should be inherited by child classes.
|
129
|
-
# @note
|
130
|
-
# - subclasses will inherit the value as is at that moment
|
131
|
-
# - any change afterwards will be only on the specific class (in line with class instance variables)
|
132
|
-
# - adapted from https://stackoverflow.com/a/10729812/4352306
|
133
|
-
# TODO: this separates the logic of the method to the instance var. Think if would be possible to join them somehow.
|
134
|
-
def inheritable_class_vars(*vars)
|
135
|
-
@inheritable_class_vars ||= [:inheritable_class_vars]
|
136
|
-
@inheritable_class_vars += vars
|
137
|
-
end
|
138
|
-
|
139
|
-
# Builds the attr_reader and attr_writer of `attrs` and registers the associated instance variable as inheritable.
|
140
|
-
def inheritable_attrs(*attrs, add_accessors: false)
|
141
|
-
if add_accessors
|
142
|
-
attrs.each do |attr|
|
143
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
144
|
-
class << self; attr_accessor :#{attr} end
|
145
|
-
RUBY
|
146
|
-
end
|
147
|
-
end
|
148
|
-
inheritable_class_vars(*attrs)
|
149
|
-
end
|
150
|
-
|
151
|
-
# This callback method is called whenever a subclass of the current class is created.
|
152
|
-
# @note
|
153
|
-
# - values of the instance variables are copied as they are (no dups or clones)
|
154
|
-
# - the above means: avoid methods that change the state of the mutable object on it
|
155
|
-
# - mutating methods would reflect the changes on other classes as well
|
156
|
-
# - therefore, `freeze` will be called on the values that are inherited.
|
157
|
-
def inherited(subclass)
|
158
|
-
super.tap do
|
159
|
-
inheritable_class_vars.each do |var|
|
160
|
-
instance_var = instance_variable_name(var)
|
161
|
-
value = instance_variable_get(instance_var)
|
162
|
-
subclass.instance_variable_set(instance_var, value.freeze)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
121
|
end
|
167
122
|
end
|
168
123
|
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
class RakeCommander
|
2
|
+
module Base
|
3
|
+
module ClassInheritable
|
4
|
+
include RakeCommander::Base::ObjectHelpers
|
5
|
+
|
6
|
+
# Builds the attr_reader and attr_writer of `attrs` and registers the associated
|
7
|
+
# instance variable as inheritable.
|
8
|
+
# @yield [value]
|
9
|
+
# @yieldparam value [Variant] the value of the parent class
|
10
|
+
# @yieldreturn the value that will be inherited by the child class
|
11
|
+
# @param attrs [Array <Symbol>] the variable names that should be inheritable.
|
12
|
+
# @param add_accessors [Boolean] whether attr_accessor should be invoked
|
13
|
+
# @param deep_dup [Boolean] whether the value of the instance var should be `deep_dup`ed.
|
14
|
+
def attr_inheritable(*attrs, add_accessors: false, deep_dup: true, &block)
|
15
|
+
attrs = attrs.map(&:to_sym)
|
16
|
+
inheritable_class_var(*attrs, deep_dup: deep_dup, &block)
|
17
|
+
return unless add_accessors
|
18
|
+
attrs.each do |attr|
|
19
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
20
|
+
class << self; attr_accessor :#{attr} end
|
21
|
+
RUBY
|
22
|
+
end
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Boolean] whether an `var` has been declared as inheritable
|
27
|
+
def inheritable_class_var?(var)
|
28
|
+
inheritable_class_var.any? do |_method, definitions|
|
29
|
+
definitions.key?(var.to_sym)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Removes from the inheritance some class variables.
|
34
|
+
# @param attrs [Array <Symbol>] the instance variable names of the class
|
35
|
+
# that should NOT be inheritable.
|
36
|
+
def attr_not_inheritable(*attrs)
|
37
|
+
attrs.each do |attr|
|
38
|
+
next unless method = inheritable_class_var_method(attr)
|
39
|
+
inheritable_class_var[method].delete(attr)
|
40
|
+
end
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# This callback method is called whenever a subclass of the current class is created.
|
47
|
+
def inherited(subclass)
|
48
|
+
super.tap do
|
49
|
+
inheritable_class_var.each do |method, definitions|
|
50
|
+
definitions.each do |var, action|
|
51
|
+
instance_var = instance_variable_name(var)
|
52
|
+
value = instance_variable_get(instance_var)
|
53
|
+
child_value = inherited_class_value(value, method, action)
|
54
|
+
subclass.instance_variable_set(instance_var, child_value)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Variant] the value that the child class will inherit
|
61
|
+
def inherited_class_value(value, method, action)
|
62
|
+
case method
|
63
|
+
when :mirror
|
64
|
+
value
|
65
|
+
when :deep_dup
|
66
|
+
case action
|
67
|
+
when Proc
|
68
|
+
action.call(value)
|
69
|
+
when :default
|
70
|
+
custom_deep_dup(value)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Keeps track on class instance variables that should be inherited by child classes.
|
76
|
+
# @note
|
77
|
+
# - adapted from https://stackoverflow.com/a/10729812/4352306
|
78
|
+
# - subclasses will inherit the value depending on `depep_dup` and `block` if enabled or given (respectivelly)
|
79
|
+
# - any change afterwards will be only on the specific class (in line with class instance variables)
|
80
|
+
# @param see `#attr_inheritable`
|
81
|
+
# @return [Hash] methods and variables to be inherited.
|
82
|
+
def inheritable_class_var(*vars, deep_dup: true, &block)
|
83
|
+
@inheritable_class_var ||= {
|
84
|
+
mirror: {},
|
85
|
+
deep_dup: {}
|
86
|
+
}.tap do |hash|
|
87
|
+
hash[:deep_dup][:inheritable_class_var] = :default
|
88
|
+
end
|
89
|
+
@inheritable_class_var.tap do |_methods|
|
90
|
+
vars.each {|var| inheritable_class_var_add(var, deep_dup: deep_dup, &block)}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Adds var to the `inheritable_class_var`
|
95
|
+
# @param var [Symbol] the name of an instance variable of this class that should be inherited.
|
96
|
+
def inheritable_class_var_add(var, deep_dup: true, &block)
|
97
|
+
# Remove previous definition if present
|
98
|
+
attr_not_inheritable(var)
|
99
|
+
method = deep_dup || block ? :deep_dup : :mirror
|
100
|
+
inheritable_class_var[method][var] = block || :default
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
# @return [Symbol, NilClass]
|
105
|
+
def inheritable_class_var_method(var)
|
106
|
+
inheritable_class_var.each do |method, definitions|
|
107
|
+
return method if definitions.key?(var.to_sym)
|
108
|
+
end
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
|
112
|
+
# Helper to create an instance variable `name`
|
113
|
+
# @param [String, Symbol] the name of the variable
|
114
|
+
# @return [String] the name of the created instance variable
|
115
|
+
def instance_variable_name(name)
|
116
|
+
str = name.to_s
|
117
|
+
str = "@#{str}" unless str.start_with?("@")
|
118
|
+
str
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class RakeCommander
|
2
|
+
module Base
|
3
|
+
# This class allows to use both method calls to `raise` by using additional parameters.
|
4
|
+
# @note Although not clearly explained, this is somehow captured here https://stackoverflow.com/a/32481520/4352306
|
5
|
+
class CustomError < StandardError
|
6
|
+
def initialize(value = nil)
|
7
|
+
super(@message = to_message(value)) if @value = value
|
8
|
+
end
|
9
|
+
|
10
|
+
# If @value was already set, ignore the latest message and
|
11
|
+
# just return @message
|
12
|
+
def to_s
|
13
|
+
return @message if @message
|
14
|
+
unclassed(super)
|
15
|
+
end
|
16
|
+
|
17
|
+
# If @value was already set, ignore the latest message
|
18
|
+
# just return @message
|
19
|
+
def message
|
20
|
+
return @message if @message
|
21
|
+
to_message(unclassed(super))
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
# Any **children classes** that want to extend how `value` is transformed
|
27
|
+
# into a `message` **should extend this method**.
|
28
|
+
# @return [String] `message`
|
29
|
+
def to_message(value)
|
30
|
+
case value
|
31
|
+
when StandardError
|
32
|
+
to_message(value.message)
|
33
|
+
when String
|
34
|
+
value
|
35
|
+
when NilClass
|
36
|
+
value
|
37
|
+
else
|
38
|
+
raise ArgumentError, "Expecting String, StandardError or NilClass. Given: #{value.class}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# When `value` is `nil` **methods** `to_s` and `message` return the error class of `self`.
|
45
|
+
# This helper allows to remove that part to know if the error was raised with `nil`
|
46
|
+
# @return [String]
|
47
|
+
def unclassed(str)
|
48
|
+
str.to_s.gsub(self.class.to_s, '').strip
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class RakeCommander
|
2
|
+
module Base
|
3
|
+
module ObjectHelpers
|
4
|
+
private
|
5
|
+
|
6
|
+
# Custom Object#deep_dup for rake commander
|
7
|
+
def custom_deep_dup(value, dup_objects: true, &dup_block)
|
8
|
+
case value
|
9
|
+
when Hash
|
10
|
+
custom_hash_deep_dup(value, dup_objects: dup_objects, &dup_block)
|
11
|
+
when Array
|
12
|
+
value.map {|v| custom_deep_dup(v, dup_objects: dup_objects, &dup_block)}
|
13
|
+
else
|
14
|
+
custom_object_deep_dup(value, dup_objects: true, &dup_block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Does the copy of the final object
|
19
|
+
def custom_object_deep_dup(value, dup_objects: true)
|
20
|
+
return yield(value) if block_given?
|
21
|
+
return value unless dup_objects
|
22
|
+
return value.deep_dup if value.respond_to?(:deep_dup)
|
23
|
+
value.dup
|
24
|
+
end
|
25
|
+
|
26
|
+
# Custom Hash#deep_dup for rake commander
|
27
|
+
def custom_hash_deep_dup(original, dup_objects: true, &dup_block)
|
28
|
+
raise ArgumentError, "Expecting Hash. Given: #{original.class}" unless original.is_a?(Hash)
|
29
|
+
hash = original.dup
|
30
|
+
original.each_pair do |key, value|
|
31
|
+
unless key.frozen? && key.is_a?(::String)
|
32
|
+
hash.delete(key)
|
33
|
+
key = custom_deep_dup(key, dup_objects: dup_objects, &dup_block) if dup_objects
|
34
|
+
end
|
35
|
+
value = dup_objects ? custom_deep_dup(value, dup_objects: dup_objects, &dup_block) : value
|
36
|
+
hash[key] = value
|
37
|
+
end
|
38
|
+
hash
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/rake-commander/base.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
require_relative 'base/object_helpers'
|
1
2
|
require_relative 'base/class_helpers'
|
3
|
+
require_relative 'base/class_inheritable'
|
2
4
|
require_relative 'base/class_auto_loader'
|
5
|
+
require_relative 'base/custom_error'
|
3
6
|
require_relative 'rake_task'
|
4
7
|
require_relative 'options'
|
5
8
|
|
@@ -8,22 +11,33 @@ class RakeCommander
|
|
8
11
|
class << self
|
9
12
|
def included(base)
|
10
13
|
super(base)
|
11
|
-
base.extend RakeCommander::Base::ClassHelpers
|
12
14
|
base.extend RakeCommander::Base::ClassAutoLoader
|
13
15
|
base.autoloads_children_of RakeCommander
|
14
16
|
|
15
17
|
base.extend ClassMethods
|
16
18
|
base.send :include, RakeTask
|
17
|
-
|
18
19
|
base.send :include, Options
|
19
20
|
#autoload_namespace_ignore "RakeCommander::Samples"
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
23
24
|
module ClassMethods
|
25
|
+
# Loads children classes by keeping a cache.
|
24
26
|
def self_load
|
25
27
|
autoload_children
|
26
28
|
end
|
29
|
+
|
30
|
+
# Clears track on any auto-loaded children
|
31
|
+
# @note required for reload.
|
32
|
+
def self_load_reset
|
33
|
+
clear_autoloaded_children
|
34
|
+
end
|
35
|
+
|
36
|
+
# Clears the cache of autoloaded children classes and loads them again.
|
37
|
+
def self_reload
|
38
|
+
self_load_reset
|
39
|
+
autoload_children
|
40
|
+
end
|
27
41
|
end
|
28
42
|
end
|
29
43
|
end
|