aspera-cli 4.14.0 → 4.16.0
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/BUGS.md +29 -3
- data/CHANGELOG.md +300 -185
- data/CONTRIBUTING.md +74 -23
- data/README.md +2346 -1619
- data/bin/ascli +16 -25
- data/bin/asession +15 -15
- data/examples/dascli +2 -2
- data/examples/proxy.pac +1 -1
- data/lib/aspera/aoc.rb +216 -150
- data/lib/aspera/ascmd.rb +25 -18
- data/lib/aspera/assert.rb +45 -0
- data/lib/aspera/cli/basic_auth_plugin.rb +9 -6
- data/lib/aspera/cli/error.rb +17 -0
- data/lib/aspera/cli/extended_value.rb +51 -16
- data/lib/aspera/cli/formatter.rb +276 -174
- data/lib/aspera/cli/hints.rb +81 -0
- data/lib/aspera/cli/main.rb +114 -147
- data/lib/aspera/cli/manager.rb +181 -136
- data/lib/aspera/cli/plugin.rb +82 -64
- data/lib/aspera/cli/plugins/alee.rb +0 -1
- data/lib/aspera/cli/plugins/aoc.rb +327 -331
- data/lib/aspera/cli/plugins/ats.rb +12 -8
- data/lib/aspera/cli/plugins/bss.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +575 -439
- data/lib/aspera/cli/plugins/console.rb +40 -0
- data/lib/aspera/cli/plugins/cos.rb +4 -5
- data/lib/aspera/cli/plugins/faspex.rb +111 -92
- data/lib/aspera/cli/plugins/faspex5.rb +245 -182
- data/lib/aspera/cli/plugins/node.rb +239 -160
- data/lib/aspera/cli/plugins/orchestrator.rb +56 -19
- data/lib/aspera/cli/plugins/preview.rb +54 -38
- data/lib/aspera/cli/plugins/server.rb +63 -20
- data/lib/aspera/cli/plugins/shares.rb +64 -38
- data/lib/aspera/cli/sync_actions.rb +68 -0
- data/lib/aspera/cli/transfer_agent.rb +64 -67
- data/lib/aspera/cli/transfer_progress.rb +73 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +3 -1
- data/lib/aspera/command_line_builder.rb +27 -22
- data/lib/aspera/cos_node.rb +6 -4
- data/lib/aspera/coverage.rb +22 -0
- data/lib/aspera/data_repository.rb +33 -2
- data/lib/aspera/environment.rb +21 -8
- data/lib/aspera/fasp/agent_alpha.rb +116 -0
- data/lib/aspera/fasp/agent_base.rb +40 -76
- data/lib/aspera/fasp/agent_connect.rb +21 -22
- data/lib/aspera/fasp/agent_direct.rb +169 -179
- data/lib/aspera/fasp/agent_httpgw.rb +200 -195
- data/lib/aspera/fasp/agent_node.rb +43 -35
- data/lib/aspera/fasp/agent_trsdk.rb +124 -41
- data/lib/aspera/fasp/error_info.rb +2 -2
- data/lib/aspera/fasp/faux_file.rb +52 -0
- data/lib/aspera/fasp/installation.rb +89 -191
- data/lib/aspera/fasp/management.rb +249 -0
- data/lib/aspera/fasp/parameters.rb +86 -47
- data/lib/aspera/fasp/parameters.yaml +75 -8
- data/lib/aspera/fasp/products.rb +162 -0
- data/lib/aspera/fasp/resume_policy.rb +7 -5
- data/lib/aspera/fasp/sync.rb +273 -0
- data/lib/aspera/fasp/transfer_spec.rb +10 -8
- data/lib/aspera/fasp/uri.rb +6 -6
- data/lib/aspera/faspex_gw.rb +11 -8
- data/lib/aspera/faspex_postproc.rb +8 -7
- data/lib/aspera/hash_ext.rb +2 -2
- data/lib/aspera/id_generator.rb +3 -1
- data/lib/aspera/json_rpc.rb +51 -0
- data/lib/aspera/keychain/encrypted_hash.rb +46 -11
- data/lib/aspera/keychain/macos_security.rb +15 -13
- data/lib/aspera/line_logger.rb +23 -0
- data/lib/aspera/log.rb +61 -19
- data/lib/aspera/nagios.rb +7 -2
- data/lib/aspera/node.rb +105 -21
- data/lib/aspera/node_simulator.rb +214 -0
- data/lib/aspera/oauth.rb +57 -36
- data/lib/aspera/open_application.rb +4 -4
- data/lib/aspera/persistency_action_once.rb +13 -14
- data/lib/aspera/persistency_folder.rb +5 -4
- data/lib/aspera/preview/file_types.rb +56 -268
- data/lib/aspera/preview/generator.rb +28 -39
- data/lib/aspera/preview/options.rb +2 -0
- data/lib/aspera/preview/terminal.rb +36 -16
- data/lib/aspera/preview/utils.rb +23 -29
- data/lib/aspera/proxy_auto_config.rb +6 -3
- data/lib/aspera/rest.rb +127 -80
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +16 -14
- data/lib/aspera/rest_errors_aspera.rb +39 -34
- data/lib/aspera/secret_hider.rb +18 -17
- data/lib/aspera/ssh.rb +10 -5
- data/lib/aspera/temp_file_manager.rb +11 -4
- data/lib/aspera/web_auth.rb +10 -7
- data/lib/aspera/web_server_simple.rb +11 -5
- data.tar.gz.sig +0 -0
- metadata +108 -39
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/listener/line_dump.rb +0 -19
- data/lib/aspera/cli/listener/logger.rb +0 -22
- data/lib/aspera/cli/listener/progress.rb +0 -50
- data/lib/aspera/cli/listener/progress_multi.rb +0 -84
- data/lib/aspera/cli/plugins/sync.rb +0 -44
- data/lib/aspera/fasp/listener.rb +0 -13
- data/lib/aspera/sync.rb +0 -213
data/lib/aspera/ascmd.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# cspell:ignore ascmd smode errstr zstr zmode zuid zgid zctime zatime zmtime fcount dcount btype blist codeset lc_ctype ascmdtypes
|
|
3
4
|
require 'aspera/log'
|
|
5
|
+
require 'aspera/assert'
|
|
4
6
|
|
|
5
7
|
module Aspera
|
|
6
8
|
# Run +ascmd+ commands using specified executor (usually, remotely on transfer node)
|
|
@@ -20,9 +22,16 @@ module Aspera
|
|
|
20
22
|
# @param [Symbol] one of OPERATIONS
|
|
21
23
|
# @param [Array] parameters for "as" command
|
|
22
24
|
# @return result of command, type depends on command (bool, array, hash)
|
|
23
|
-
def execute_single(action_sym,
|
|
24
|
-
#
|
|
25
|
-
|
|
25
|
+
def execute_single(action_sym, arguments=nil)
|
|
26
|
+
# add "as_" command
|
|
27
|
+
main_command = ["as_#{action_sym}"]
|
|
28
|
+
arguments&.each do |v|
|
|
29
|
+
# enclose arguments in double quotes, protect backslash and double quotes
|
|
30
|
+
main_command.push(%Q{"#{v.gsub(/["\\]/n){|s|"\\#{s}"}}"})
|
|
31
|
+
end
|
|
32
|
+
# execute the main command and then exit
|
|
33
|
+
stdin_input = [main_command.join(' '), 'as_exit', ''].join("\n")
|
|
34
|
+
Log.log.debug{"execute_single:#{stdin_input}"}
|
|
26
35
|
# execute, get binary output
|
|
27
36
|
byte_buffer = @command_executor.execute('ascmd', stdin_input).unpack('C*')
|
|
28
37
|
raise 'ERROR: empty answer from server' if byte_buffer.empty?
|
|
@@ -44,29 +53,27 @@ module Aspera
|
|
|
44
53
|
end
|
|
45
54
|
end
|
|
46
55
|
# for info, second overrides first, so restore it
|
|
47
|
-
case result.keys.length; when 0 then result = system_info; when 1 then result = result[result.keys.first]; else
|
|
56
|
+
case result.keys.length; when 0 then result = system_info; when 1 then result = result[result.keys.first]; else error_unexpected_value(result.keys.length); end
|
|
48
57
|
# raise error as exception
|
|
49
|
-
raise Error.new(result[:errno], result[:errstr], action_sym,
|
|
58
|
+
raise Error.new(result[:errno], result[:errstr], action_sym, arguments) if
|
|
50
59
|
result.is_a?(Hash) && (result.keys.sort == TYPES_DESCR[:error][:fields].map{|i|i[:name]}.sort)
|
|
51
60
|
return result
|
|
52
61
|
end # execute_single
|
|
53
62
|
|
|
54
63
|
# This exception is raised when +ascmd+ returns an error.
|
|
55
64
|
class Error < StandardError
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def initialize(errno, errstr, cmd, args); super(); @errno = errno; @errstr = errstr; @command = cmd; @args = args; end # rubocop:disable Style/Semicolon
|
|
59
|
-
|
|
60
|
-
def message; "ascmd: (#{errno}) #{errstr}"; end
|
|
65
|
+
def initialize(errno, errstr, cmd, arguments)
|
|
66
|
+
super(); @errno = errno; @errstr = errstr; @command = cmd; @arguments = arguments; end # rubocop:disable Style/Semicolon
|
|
61
67
|
|
|
62
|
-
def
|
|
68
|
+
def message; "ascmd: #{@errstr} (#{@errno})"; end
|
|
69
|
+
def extended_message; "ascmd: errno=#{@errno} errstr=\"#{@errstr}\" command=#{@command} arguments=#{@arguments.join(',')}"; end
|
|
63
70
|
end # Error
|
|
64
71
|
|
|
65
72
|
# description of result structures (see ascmdtypes.h). Base types are big endian
|
|
66
73
|
# key = name of type
|
|
67
74
|
TYPES_DESCR = {
|
|
68
75
|
result: {decode: :field_list,
|
|
69
|
-
fields: [{name: :file, is_a: :stat}, {name: :dir, is_a: :stat, special: :
|
|
76
|
+
fields: [{name: :file, is_a: :stat}, {name: :dir, is_a: :stat, special: :sub_struct}, {name: :size, is_a: :size}, {name: :error, is_a: :error},
|
|
70
77
|
{name: :info, is_a: :info}, {name: :success, is_a: nil, special: :return_true}, {name: :exit, is_a: nil},
|
|
71
78
|
{name: :df, is_a: :mnt, special: :restart_on_first}, {name: :md5sum, is_a: :md5sum}]},
|
|
72
79
|
stat: {decode: :field_list,
|
|
@@ -118,7 +125,7 @@ module Aspera
|
|
|
118
125
|
indent_level = (indent_level || -1) + 1
|
|
119
126
|
type_descr = TYPES_DESCR[type_name]
|
|
120
127
|
raise "Unexpected type #{type_name}" if type_descr.nil?
|
|
121
|
-
Log.log.
|
|
128
|
+
Log.log.trace1{"#{' .' * indent_level}parse:#{type_name}:#{type_descr[:decode]}:#{buffer[0, 16]}...".red}
|
|
122
129
|
result = nil
|
|
123
130
|
case type_descr[:decode]
|
|
124
131
|
when :base
|
|
@@ -128,7 +135,7 @@ module Aspera
|
|
|
128
135
|
byte_array = [byte_array] unless byte_array.is_a?(Array)
|
|
129
136
|
result = byte_array.pack('C*').unpack1(type_descr[:unpack])
|
|
130
137
|
result.force_encoding('UTF-8') if type_name.eql?(:zstr)
|
|
131
|
-
Log.log.
|
|
138
|
+
Log.log.trace1{"#{' .' * indent_level}-> base:#{byte_array} -> #{result}"}
|
|
132
139
|
result = Time.at(result) if type_name.eql?(:epoch)
|
|
133
140
|
when :buffer_list
|
|
134
141
|
result = []
|
|
@@ -138,7 +145,7 @@ module Aspera
|
|
|
138
145
|
raise 'ERROR:not enough bytes' if buffer.length < length
|
|
139
146
|
value = buffer.shift(length)
|
|
140
147
|
result.push({btype: btype, buffer: value})
|
|
141
|
-
Log.log.
|
|
148
|
+
Log.log.trace1{"#{' .' * indent_level}:buffer_list[#{result.length - 1}] #{result.last}"}
|
|
142
149
|
end
|
|
143
150
|
when :field_list
|
|
144
151
|
# by default the result is one struct
|
|
@@ -147,13 +154,13 @@ module Aspera
|
|
|
147
154
|
parse(buffer, :blist, indent_level).each do |typed_buffer|
|
|
148
155
|
# what type of field is it ?
|
|
149
156
|
field_info = field_description(type_name, typed_buffer)
|
|
150
|
-
Log.log.
|
|
157
|
+
Log.log.trace1{"#{' .' * indent_level}+ field(special=#{field_info[:special]})=#{field_info[:name]}".green}
|
|
151
158
|
case field_info[:special]
|
|
152
159
|
when nil
|
|
153
160
|
result[field_info[:name]] = parse(typed_buffer[:buffer], field_info[:is_a], indent_level)
|
|
154
161
|
when :return_true
|
|
155
162
|
result[field_info[:name]] = true
|
|
156
|
-
when :
|
|
163
|
+
when :sub_struct
|
|
157
164
|
result[field_info[:name]] = parse(typed_buffer[:buffer], :blist, indent_level).map{|r|parse(r[:buffer], field_info[:is_a], indent_level)}
|
|
158
165
|
when :multiple
|
|
159
166
|
result[field_info[:name]] ||= []
|
|
@@ -167,7 +174,7 @@ module Aspera
|
|
|
167
174
|
end
|
|
168
175
|
end
|
|
169
176
|
end
|
|
170
|
-
else
|
|
177
|
+
else error_unexpected_value(type_descr[:decode])
|
|
171
178
|
end # is_a
|
|
172
179
|
return result
|
|
173
180
|
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aspera
|
|
4
|
+
class InternalError < StandardError
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class AssertError < StandardError
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Object
|
|
12
|
+
def assert(assertion, info = nil, level: 2, exception_class: Aspera::AssertError)
|
|
13
|
+
raise Aspera::InternalError, 'bad assert: both info and block given' unless info.nil? || !block_given?
|
|
14
|
+
return if assertion
|
|
15
|
+
message = 'assertion failed'
|
|
16
|
+
info = yield if block_given?
|
|
17
|
+
message = "#{message}: #{info}" if info
|
|
18
|
+
message = "#{message}: #{caller(level..level).first}"
|
|
19
|
+
raise exception_class, message
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# assert that value has the given type
|
|
23
|
+
# @param value [Object] the value to check
|
|
24
|
+
# @param type [Class] the expected type
|
|
25
|
+
def assert_type(value, type, exception_class: Aspera::AssertError)
|
|
26
|
+
assert(value.is_a?(type), level: 3, exception_class: exception_class){"#{block_given? ? "#{yield}: " : nil}expecting #{type}, but have #{value.inspect}"}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# assert that value is one of the given values
|
|
30
|
+
def assert_values(value, values, exception_class: Aspera::AssertError)
|
|
31
|
+
assert(values.include?(value), level: 3, exception_class: exception_class) do
|
|
32
|
+
"#{block_given? ? "#{yield}: " : nil}expecting one of #{values.inspect}, but have #{value.inspect}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# the line with this shall never be reached
|
|
37
|
+
def error_unreachable_line
|
|
38
|
+
raise Aspera::InternalError, "unreachable line reached: #{caller(2..2).first}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# the value is not one of the expected values
|
|
42
|
+
def error_unexpected_value(value, exception_class: Aspera::InternalError)
|
|
43
|
+
raise exception_class, "#{block_given? ? "#{yield}: " : nil}unexpected value: #{value.inspect}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -8,17 +8,20 @@ module Aspera
|
|
|
8
8
|
# base class for applications supporting basic authentication
|
|
9
9
|
class BasicAuthPlugin < Aspera::Cli::Plugin
|
|
10
10
|
class << self
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
@@basic_options_declared = false # rubocop:disable Style/ClassVars
|
|
12
|
+
def declare_options(options, force: false)
|
|
13
|
+
return if @@basic_options_declared && !force
|
|
14
|
+
@@basic_options_declared = true # rubocop:disable Style/ClassVars
|
|
15
|
+
options.declare(:url, 'URL of application, e.g. https://faspex.example.com/aspera/faspex')
|
|
16
|
+
options.declare(:username, 'Username to log in')
|
|
17
|
+
options.declare(:password, "User's password")
|
|
18
|
+
options.parse_options!
|
|
16
19
|
end
|
|
17
20
|
end
|
|
18
21
|
|
|
19
22
|
def initialize(env)
|
|
20
23
|
super(env)
|
|
21
|
-
|
|
24
|
+
BasicAuthPlugin.declare_options(options, force: env[:all_manuals])
|
|
22
25
|
end
|
|
23
26
|
|
|
24
27
|
# returns a Rest object with basic auth
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aspera
|
|
4
|
+
module Cli
|
|
5
|
+
# CLI base exception
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
|
|
8
|
+
# raised when an unexpected argument is provided
|
|
9
|
+
class BadArgument < Error; end
|
|
10
|
+
|
|
11
|
+
class NoSuchIdentifier < Error
|
|
12
|
+
def initialize(res_type, res_id)
|
|
13
|
+
super("#{res_type} with identifier #{res_id} not found")
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# cspell:ignore csvt jsonpp
|
|
3
4
|
require 'aspera/uri_reader'
|
|
4
5
|
require 'aspera/environment'
|
|
6
|
+
require 'aspera/log'
|
|
7
|
+
require 'aspera/assert'
|
|
5
8
|
require 'json'
|
|
6
9
|
require 'base64'
|
|
7
10
|
require 'zlib'
|
|
@@ -14,6 +17,11 @@ module Aspera
|
|
|
14
17
|
class ExtendedValue
|
|
15
18
|
include Singleton
|
|
16
19
|
|
|
20
|
+
# special values
|
|
21
|
+
INIT = 'INIT'
|
|
22
|
+
ALL = 'ALL'
|
|
23
|
+
DEF = 'DEF'
|
|
24
|
+
|
|
17
25
|
class << self
|
|
18
26
|
# decode comma separated table text
|
|
19
27
|
def decode_csvt(value)
|
|
@@ -24,35 +32,42 @@ module Aspera
|
|
|
24
32
|
if col_titles.nil?
|
|
25
33
|
col_titles = values
|
|
26
34
|
else
|
|
27
|
-
|
|
28
|
-
col_titles.each{|title|entry[title] = values.shift}
|
|
29
|
-
hash_array.push(entry)
|
|
35
|
+
hash_array.push(col_titles.zip(values).to_h)
|
|
30
36
|
end
|
|
31
37
|
end
|
|
32
38
|
Log.log.warn('Titled CSV file without any line') if hash_array.empty?
|
|
33
39
|
return hash_array
|
|
34
40
|
end
|
|
41
|
+
|
|
42
|
+
def assert_no_value(v, what)
|
|
43
|
+
raise "no value allowed for extended value type: #{what}" unless v.empty?
|
|
44
|
+
end
|
|
35
45
|
end
|
|
36
46
|
|
|
37
47
|
private
|
|
38
48
|
|
|
39
49
|
def initialize
|
|
50
|
+
# base handlers
|
|
51
|
+
# other handlers can be set using set_handler, e.g. `preset` is reader in config plugin
|
|
40
52
|
@handlers = {
|
|
53
|
+
val: lambda{|v|v},
|
|
41
54
|
base64: lambda{|v|Base64.decode64(v)},
|
|
42
55
|
csvt: lambda{|v|ExtendedValue.decode_csvt(v)},
|
|
43
|
-
env: lambda{|v|ENV
|
|
56
|
+
env: lambda{|v|ENV.fetch(v, nil)},
|
|
44
57
|
file: lambda{|v|File.read(File.expand_path(v))},
|
|
58
|
+
uri: lambda{|v|UriReader.read(v)},
|
|
45
59
|
json: lambda{|v|JSON.parse(v)},
|
|
46
60
|
lines: lambda{|v|v.split("\n")},
|
|
47
61
|
list: lambda{|v|v[1..-1].split(v[0])},
|
|
62
|
+
none: lambda{|v|ExtendedValue.assert_no_value(v, :none); nil}, # rubocop:disable Style/Semicolon
|
|
48
63
|
path: lambda{|v|File.expand_path(v)},
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
zlib: lambda{|v|Zlib::Inflate.inflate(v)}
|
|
55
|
-
|
|
64
|
+
re: lambda{|v|Regexp.new(v)},
|
|
65
|
+
ruby: lambda{|v|Environment.secure_eval(v, __FILE__, __LINE__)},
|
|
66
|
+
secret: lambda{|v|prompt = v.empty? ? 'secret' : v; $stdin.getpass("#{prompt}> ")}, # rubocop:disable Style/Semicolon
|
|
67
|
+
stdin: lambda{|v|ExtendedValue.assert_no_value(v, :stdin); $stdin.read}, # rubocop:disable Style/Semicolon
|
|
68
|
+
yaml: lambda{|v|YAML.load(v)},
|
|
69
|
+
zlib: lambda{|v|Zlib::Inflate.inflate(v)},
|
|
70
|
+
extend: lambda{|v|ExtendedValue.instance.evaluate_all(v)}
|
|
56
71
|
}
|
|
57
72
|
end
|
|
58
73
|
|
|
@@ -63,25 +78,45 @@ module Aspera
|
|
|
63
78
|
# add a new handler
|
|
64
79
|
def set_handler(name, method)
|
|
65
80
|
Log.log.debug{"setting handler for #{name}"}
|
|
66
|
-
|
|
81
|
+
assert_type(name, Symbol){'name'}
|
|
67
82
|
@handlers[name] = method
|
|
68
83
|
end
|
|
69
84
|
|
|
85
|
+
# Regex to match an extended value
|
|
86
|
+
def ext_re
|
|
87
|
+
"@(#{modifiers.join('|')}):"
|
|
88
|
+
end
|
|
89
|
+
|
|
70
90
|
# parse an option value if it is a String using supported extended value modifiers
|
|
71
91
|
# other value types are returned as is
|
|
72
92
|
def evaluate(value)
|
|
73
|
-
return value
|
|
93
|
+
return value unless value.is_a?(String)
|
|
94
|
+
regex = Regexp.new("^#{ext_re}(.*)$")
|
|
74
95
|
# first determine decoders, in reversed order
|
|
75
96
|
handlers_reversed = []
|
|
76
|
-
while (m = value.match(
|
|
77
|
-
|
|
97
|
+
while (m = value.match(regex))
|
|
98
|
+
handler = m[1].to_sym
|
|
99
|
+
handlers_reversed.unshift(handler)
|
|
78
100
|
value = m[2]
|
|
101
|
+
# stop processing if handler is extend (it will be processed later)
|
|
102
|
+
break if handler.eql?(:extend)
|
|
79
103
|
end
|
|
80
104
|
handlers_reversed.each do |handler|
|
|
81
105
|
value = @handlers[handler].call(value)
|
|
82
106
|
end
|
|
83
107
|
return value
|
|
84
|
-
end #
|
|
108
|
+
end # evaluate
|
|
109
|
+
|
|
110
|
+
# find inner extended values
|
|
111
|
+
def evaluate_all(value)
|
|
112
|
+
regex = Regexp.new("^(.*)#{ext_re}([^@]*)@(.*)$")
|
|
113
|
+
while (m = value.match(regex))
|
|
114
|
+
sub_value = "@#{m[2]}:#{m[3]}"
|
|
115
|
+
Log.log.debug("evaluating #{sub_value}")
|
|
116
|
+
value = m[1] + evaluate(sub_value) + m[4]
|
|
117
|
+
end
|
|
118
|
+
return value
|
|
119
|
+
end
|
|
85
120
|
end
|
|
86
121
|
end
|
|
87
122
|
end
|