ltdtemplate 0.2.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +10 -1
- data/Gemfile +2 -1
- data/RESOURCES +18 -32
- data/TEMPLATE_MANUAL.html +126 -47
- data/lib/ltdtemplate.rb +352 -242
- data/lib/ltdtemplate/code.rb +14 -87
- data/lib/ltdtemplate/code/call.rb +20 -16
- data/lib/ltdtemplate/code/parameters.rb +28 -31
- data/lib/ltdtemplate/code/sequence.rb +39 -0
- data/lib/ltdtemplate/code/subscript.rb +57 -50
- data/lib/ltdtemplate/code/variable.rb +22 -39
- data/lib/ltdtemplate/proxy.rb +26 -0
- data/lib/ltdtemplate/proxy/array.rb +258 -0
- data/lib/ltdtemplate/proxy/boolean.rb +74 -0
- data/lib/ltdtemplate/proxy/match.rb +40 -0
- data/lib/ltdtemplate/proxy/nil.rb +27 -0
- data/lib/ltdtemplate/proxy/number.rb +77 -0
- data/lib/ltdtemplate/proxy/regexp.rb +74 -0
- data/lib/ltdtemplate/proxy/string.rb +196 -0
- data/lib/ltdtemplate/value.rb +94 -0
- data/lib/ltdtemplate/value/array_splat.rb +34 -0
- data/lib/ltdtemplate/value/code_block.rb +21 -17
- data/lib/ltdtemplate/value/namespace.rb +77 -79
- data/ltdtemplate.gemspec +2 -2
- data/test/04number.rb +0 -7
- data/test/05string.rb +0 -7
- data/test/06array.rb +0 -9
- data/test/07each.rb +3 -3
- data/test/08interpolate.rb +1 -1
- data/test/10missing_meth.rb +1 -1
- data/test/11classes.rb +9 -9
- metadata +15 -13
- data/lib/ltdtemplate/code/code_block.rb +0 -30
- data/lib/ltdtemplate/value/array.rb +0 -210
- data/lib/ltdtemplate/value/boolean.rb +0 -82
- data/lib/ltdtemplate/value/nil.rb +0 -30
- data/lib/ltdtemplate/value/number.rb +0 -96
- data/lib/ltdtemplate/value/string.rb +0 -215
- data/lib/test.rb +0 -10
- data/test/03tpl_singletons.rb +0 -48
data/lib/ltdtemplate/code.rb
CHANGED
@@ -1,103 +1,30 @@
|
|
1
|
-
# LtdTemplate::Code - Base class for LtdTemplate code
|
1
|
+
# LtdTemplate::Code - Base class for LtdTemplate code objects
|
2
2
|
#
|
3
|
-
# @author Brian Katzung
|
4
|
-
# @copyright 2013 Brian Katzung and Kappa Computer Solutions, LLC
|
3
|
+
# @author Brian Katzung (briank@kappacs.com), Kappa Computer Solutions, LLC
|
4
|
+
# @copyright 2013-2014 Brian Katzung and Kappa Computer Solutions, LLC
|
5
5
|
# @license MIT License
|
6
6
|
|
7
|
-
|
7
|
+
require 'ltdtemplate'
|
8
8
|
|
9
9
|
class LtdTemplate::Code
|
10
10
|
|
11
|
-
#
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# Return a new factory object instance (or a singleton in some
|
17
|
-
# subclasses, e.g. nil).
|
18
|
-
#
|
19
|
-
# @param args [Array] Class-specific initializer parameters.
|
20
|
-
def self.instance (*args); self.new(*args); end
|
11
|
+
# All derived classes are initialized with the template object and
|
12
|
+
# handle their own template methods.
|
13
|
+
extend LtdTemplate::Consumer
|
14
|
+
include LtdTemplate::Method_Handler
|
21
15
|
|
22
16
|
# Initialize the object with a link to the associated template.
|
23
17
|
#
|
24
18
|
# @param template [LtdTemplate] The associated template object.
|
25
|
-
def initialize (template)
|
26
|
-
@template = template
|
27
|
-
@tpl_methods = {}
|
28
|
-
end
|
29
|
-
|
30
|
-
# Does a non-array value have a particular template method?
|
31
|
-
#
|
32
|
-
# @param key [String] The (native) string for the method.
|
33
|
-
# @return [Boolean]
|
34
|
-
def has_item? (key); @tpl_methods.has_key? key; end
|
35
|
-
|
36
|
-
# Return a non-array value's method code block (if set).
|
37
|
-
#
|
38
|
-
# @param key [String] The (native) string for the method.
|
39
|
-
# @return [LtdTemplate::Value::Code_Block]
|
40
|
-
def get_item (key)
|
41
|
-
(@tpl_methods.has_key? key) ? @tpl_methods[key] : @template.nil
|
42
|
-
end
|
19
|
+
def initialize (template); @template = template; end
|
43
20
|
|
44
|
-
|
45
|
-
|
46
|
-
# @param key [String] The (native) string for the method.
|
47
|
-
# @param value [LtdTemplate::Value::Code_Block] The code block
|
48
|
-
# for the method.
|
49
|
-
def set_item (key, value); @tpl_methods[key] = value; end
|
50
|
-
|
51
|
-
# No-op setting a value. (Typically only variables can change their
|
52
|
-
# primary values.)
|
53
|
-
#
|
54
|
-
# @param value The value to set. (Ignored.)
|
55
|
-
# @return [LtdTemplate::Code]
|
56
|
-
def set_value (value); self; end
|
57
|
-
|
58
|
-
# Is this value set? Always true except for unset variables.
|
59
|
-
#
|
60
|
-
# @return [true]
|
61
|
-
def is_set?; true; end
|
62
|
-
|
63
|
-
# Implement "=" (assignment). Note that set_value is a no-op except
|
64
|
-
# for variables and array subscripts.
|
65
|
-
#
|
66
|
-
# @param opts [Hash] A hash of method options.
|
67
|
-
# @option opts [LtdTemplate::Value::Parameters] :parameters The method
|
68
|
-
# parameters.
|
69
|
-
# @return [LtdTemplate::Value::Nil]
|
70
|
-
def do_set (opts)
|
71
|
-
if params = opts[:parameters]
|
72
|
-
set_value(params.scalar? ? params.positional[0] : params)
|
73
|
-
end
|
74
|
-
@template.nil
|
21
|
+
def inspect
|
22
|
+
"#<#{self.class.name}##{self.object_id} for #{@template.inspect}>"
|
75
23
|
end
|
76
24
|
|
77
|
-
#
|
78
|
-
|
79
|
-
def do_method (opts, class_name = nil)
|
80
|
-
method = nil
|
81
|
-
if name = opts[:method]
|
82
|
-
if @tpl_methods.has_key? name
|
83
|
-
method = @tpl_methods[name]
|
84
|
-
elsif class_name
|
85
|
-
class_var = @template.factory :variable, class_name
|
86
|
-
method = class_var.target.tpl_methods[name] if
|
87
|
-
class_var.is_set?
|
88
|
-
end
|
89
|
-
end
|
90
|
-
if method
|
91
|
-
opts[:target] = self
|
92
|
-
method.get_value opts
|
93
|
-
elsif mmproc = @template.options[:missing_method]
|
94
|
-
mmproc.call(@template, self, opts) || @template.nil
|
95
|
-
else
|
96
|
-
@template.nil
|
97
|
-
end
|
98
|
-
end
|
25
|
+
# Shortcut to rubyversed in the template.
|
26
|
+
def rubyversed (obj); @template.rubyversed(obj); end
|
99
27
|
|
100
28
|
end
|
101
29
|
|
102
|
-
#
|
103
|
-
class LtdTemplate::Value; end
|
30
|
+
# END
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# LtdTemplate::Code::Call - Represents a method call in an LtdTemplate
|
2
2
|
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
3
|
+
# @author Brian Katzung (briank@kappacs.com), Kappa Computer Solutions, LLC
|
4
|
+
# @copyright 2013-2014 Brian Katzung and Kappa Computer Solutions, LLC
|
5
|
+
# @license MIT License
|
6
6
|
|
7
7
|
require 'ltdtemplate/code'
|
8
8
|
|
@@ -11,9 +11,10 @@ class LtdTemplate::Code::Call < LtdTemplate::Code
|
|
11
11
|
# Initialize a method call object.
|
12
12
|
#
|
13
13
|
# @param template [LtdTemplate] The template object
|
14
|
-
# @param target
|
15
|
-
# @param method [String] The method to
|
16
|
-
# @param parameters [LtdTemplate::Code::Parameters]
|
14
|
+
# @param target (Code for) the target to call
|
15
|
+
# @param method [String] The method to invoke
|
16
|
+
# @param parameters [LtdTemplate::Code::Parameters] Code blocks for
|
17
|
+
# the method parameters
|
17
18
|
def initialize (template, target, method, parameters)
|
18
19
|
super template
|
19
20
|
@target, @method, @parameters = target, method, parameters
|
@@ -23,24 +24,27 @@ class LtdTemplate::Code::Call < LtdTemplate::Code
|
|
23
24
|
#
|
24
25
|
# @param opts [Hash] Option hash
|
25
26
|
# @option opts [String] :method A method to call on the return value
|
26
|
-
def
|
27
|
+
def evaluate (opts = {})
|
27
28
|
# Increase the call count and call depth.
|
29
|
+
# RESOURCE calls: Total number of method calls
|
28
30
|
@template.use :calls
|
31
|
+
# RESOURCE call_depth: The current method call depth
|
29
32
|
@template.use :call_depth
|
30
33
|
|
31
|
-
|
32
|
-
|
34
|
+
# Invoke the method call that we encode against the target.
|
35
|
+
result = rubyversed(@target).evaluate({ :method => @method,
|
36
|
+
:parameters => rubyversed(@parameters).evaluate })
|
33
37
|
|
34
38
|
# Decrease the call depth.
|
35
39
|
@template.use :call_depth, -1
|
36
40
|
|
37
|
-
|
38
|
-
|
41
|
+
# Invoke the method call requested by our invoker against the result.
|
42
|
+
result = rubyversed(result).evaluate({ :method => opts[:method],
|
43
|
+
:parameters => opts[:parameters] }) if opts[:method]
|
39
44
|
|
40
|
-
|
41
|
-
|
42
|
-
def has_item? (key); get_value.has_item? key; end
|
43
|
-
def get_item (key); get_value.get_item key; end
|
44
|
-
def set_item (key, value); get_value.set_item key, value; end
|
45
|
+
result
|
46
|
+
end
|
45
47
|
|
46
48
|
end
|
49
|
+
|
50
|
+
# END
|
@@ -5,15 +5,16 @@
|
|
5
5
|
# License:: MIT License
|
6
6
|
|
7
7
|
require 'ltdtemplate/code'
|
8
|
+
require 'ltdtemplate/value/array_splat'
|
9
|
+
|
10
|
+
module LtdTemplate::Univalue; end
|
8
11
|
|
9
12
|
class LtdTemplate::Code::Parameters < LtdTemplate::Code
|
10
13
|
|
11
14
|
attr_reader :positional, :named
|
12
15
|
|
13
|
-
#
|
14
16
|
# Create a parameter list builder with code to generate positional
|
15
17
|
# values and possibly code to generate named values.
|
16
|
-
#
|
17
18
|
def initialize (template, positional = [], named = nil)
|
18
19
|
super template
|
19
20
|
|
@@ -21,48 +22,44 @@ class LtdTemplate::Code::Parameters < LtdTemplate::Code
|
|
21
22
|
@positional, @named = positional, named
|
22
23
|
end
|
23
24
|
|
24
|
-
#
|
25
25
|
# Evaluate the code provided for the positional and named parameters
|
26
|
-
# and return a corresponding
|
26
|
+
# and return a corresponding Sarah.
|
27
27
|
#
|
28
|
-
|
29
|
-
|
28
|
+
# @return [Sarah]
|
29
|
+
def evaluate (opts = {})
|
30
|
+
params = @template.factory :array
|
30
31
|
|
31
32
|
# Process the positional parameters (pos1, ..., posN)
|
32
|
-
|
33
|
-
|
34
|
-
if
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
33
|
+
@positional.each do |code|
|
34
|
+
value = rubyversed(code).evaluate
|
35
|
+
if value.is_a? LtdTemplate::Value::Array_Splat
|
36
|
+
# Merge parameters from array/ or array%
|
37
|
+
# RESOURCE array_growth: Increases in array sizes
|
38
|
+
@template.use :array_growth, value.positional.size
|
39
|
+
params.concat value.positional
|
40
|
+
if value.named
|
41
|
+
@template.use :array_growth, value.named.size / 2
|
42
|
+
params.set_pairs *value.named
|
43
43
|
end
|
44
|
-
|
45
|
-
else val
|
44
|
+
else params.push value
|
46
45
|
end
|
47
|
-
end
|
46
|
+
end
|
48
47
|
|
49
48
|
# Process the named parameters (.. key1, val1, ..., keyN, valN)
|
50
49
|
if @named
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
named[key.get_value.to_native] = val.get_value if val
|
55
|
-
end
|
50
|
+
@named.each_slice(2) do |k_code, v_code|
|
51
|
+
params[rubyversed(k_code).evaluate] =
|
52
|
+
rubyversed(v_code).evaluate if v_code
|
56
53
|
end
|
57
|
-
scalar = false
|
58
|
-
else
|
59
|
-
scalar = (positional.size == 1) && named.empty?
|
60
54
|
end
|
61
55
|
|
62
|
-
|
56
|
+
# Is this a candidate for scalar assignment?
|
57
|
+
params.extend LtdTemplate::Univalue if
|
58
|
+
!@named && params.size(:seq) == 1
|
63
59
|
|
64
|
-
|
65
|
-
opts[:method] ? array.get_value(opts) : array
|
60
|
+
params
|
66
61
|
end
|
67
62
|
|
68
63
|
end
|
64
|
+
|
65
|
+
# END
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# LtdTemplate::Code::Sequence - Represents a code sequence (a list of
|
2
|
+
# code steps) in an LtdTemplate
|
3
|
+
#
|
4
|
+
# Code sequences do not accept parameters or generate new namespaces.
|
5
|
+
# They are used for things like call parameters and subscript expressions.
|
6
|
+
# See also: LtdTemplate::Value::Code_Block.
|
7
|
+
#
|
8
|
+
# @author Brian Katzung <briank@kappacs.com>, Kappa Computer Solutions, LLC
|
9
|
+
# @copyright 2013-2014 Brian Katzung and Kappa Computer Solutions, LLC
|
10
|
+
# @license MIT License
|
11
|
+
|
12
|
+
require 'ltdtemplate/code'
|
13
|
+
|
14
|
+
class LtdTemplate::Code::Sequence < LtdTemplate::Code
|
15
|
+
|
16
|
+
def initialize (template, code)
|
17
|
+
super template
|
18
|
+
@code = code
|
19
|
+
end
|
20
|
+
|
21
|
+
# Evaluate the code sequence.
|
22
|
+
def evaluate (opts = {})
|
23
|
+
values = @code.map do |code|
|
24
|
+
# RESOURCE code_steps: Total number of code steps executed
|
25
|
+
@template.use :code_steps
|
26
|
+
rubyversed(code).evaluate
|
27
|
+
end
|
28
|
+
case values.size
|
29
|
+
when 0 then nil
|
30
|
+
when 1 then values[0]
|
31
|
+
else values.map { |val| rubyversed(val).tpl_text }.join('').
|
32
|
+
tap { |res| @template.using :string_length, res.length }
|
33
|
+
# RESOURCE string_length: Length of longest modified string
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
# END
|
@@ -1,11 +1,12 @@
|
|
1
1
|
# LtdTemplate::Code::Subscript - Represents an array subscript in
|
2
2
|
# an LtdTemplate
|
3
3
|
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
4
|
+
# @author Brian Katzung <briank@kappacs.com>, Kappa Computer Solutions, LLC
|
5
|
+
# @copyright 2013-2014 Brian Katzung and Kappa Computer Solutions, LLC
|
6
|
+
# @license MIT License
|
7
7
|
|
8
8
|
require 'ltdtemplate/code'
|
9
|
+
require 'ltdtemplate/value/array_splat'
|
9
10
|
|
10
11
|
class LtdTemplate::Code::Subscript < LtdTemplate::Code
|
11
12
|
|
@@ -15,67 +16,73 @@ class LtdTemplate::Code::Subscript < LtdTemplate::Code
|
|
15
16
|
end
|
16
17
|
|
17
18
|
#
|
18
|
-
#
|
19
|
+
# Evaluate the target's value.
|
19
20
|
#
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
if usage and num_subs > 0
|
25
|
-
@template.using :subscript_depth, num_subs
|
26
|
-
@template.use :subscripts, num_subs
|
21
|
+
def evaluate (opts = {})
|
22
|
+
case opts[:method]
|
23
|
+
when '=', '?=' then do_set opts # Support array assignment
|
24
|
+
else rubyversed(target(true)).evaluate opts
|
27
25
|
end
|
28
|
-
nsubs
|
29
26
|
end
|
30
27
|
|
31
28
|
#
|
32
|
-
# Return
|
29
|
+
# Return subscripts calculated from the supplied code blocks.
|
33
30
|
#
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
31
|
+
def evaluate_subscripts (meter = false)
|
32
|
+
subscripts = []
|
33
|
+
@subscripts.each do |code|
|
34
|
+
subscript = rubyversed(code).evaluate
|
35
|
+
case subscript
|
36
|
+
when LtdTemplate::Value::Array_Splat
|
37
|
+
if meter && (size = subscript.positional.size) > 1
|
38
|
+
# RESOURCE subscripts: Total number of subscripts
|
39
|
+
# RESOURCE subscript_depth: Deepest subscript depth
|
40
|
+
@template.use :subscripts, size - 1
|
41
|
+
@template.using :subscript_depth, size
|
42
|
+
end
|
43
|
+
subscripts.concat subscript.positional
|
44
|
+
when Numeric, String then subscripts << subscript
|
45
|
+
end
|
46
|
+
end
|
39
47
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
48
|
+
if meter
|
49
|
+
@template.use :subscripts, @subscripts.size
|
50
|
+
@template.using :subscript_depth, subscripts.size
|
51
|
+
end
|
52
|
+
|
53
|
+
subscripts
|
54
|
+
end
|
46
55
|
|
47
56
|
#
|
48
|
-
#
|
57
|
+
# Return the target value, variable[sub1, ..., subN]
|
49
58
|
#
|
50
|
-
def
|
51
|
-
|
52
|
-
if
|
53
|
-
|
54
|
-
@base.set_value value
|
55
|
-
else
|
56
|
-
#
|
57
|
-
# Traverse all but the last subscript, trying to autovivicate
|
58
|
-
# new arrays as we go. This will silently fail if there is an
|
59
|
-
# existing non-array value somewhere.
|
60
|
-
#
|
61
|
-
current = @base
|
62
|
-
current.set_value @template.factory :array unless current.is_set?
|
63
|
-
subs[0..-2].each do |sub|
|
64
|
-
if !current.has_item? sub
|
65
|
-
current.set_item sub, @template.factory(:array)
|
66
|
-
end
|
67
|
-
current = current.get_item sub
|
68
|
-
end
|
69
|
-
current.set_item subs[-1], value
|
59
|
+
def target (meter = false)
|
60
|
+
subscripts = evaluate_subscripts meter
|
61
|
+
if subscripts.empty? then rubyversed(@base).evaluate
|
62
|
+
else rubyversed(@base).evaluate.in_rubyverse(@template)[*subscripts, {}]
|
70
63
|
end
|
71
|
-
self
|
72
64
|
end
|
73
65
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
66
|
+
##################################################
|
67
|
+
|
68
|
+
# Implement = and ?=
|
69
|
+
def do_set (opts)
|
70
|
+
subscripts = evaluate_subscripts true
|
71
|
+
if subscripts.empty?
|
72
|
+
# Treat expression[] as expression
|
73
|
+
rubyversed(@base).evaluate opts
|
74
|
+
elsif opts[:method] != '?=' ||
|
75
|
+
rubyversed(@base).evaluate.in_rubyverse(@template)[*subscripts,
|
76
|
+
{}].nil?
|
77
|
+
# Assign if unconditional or unset
|
78
|
+
params = opts[:parameters]
|
79
|
+
params = params[0] if params.is_a? LtdTemplate::Univalue
|
80
|
+
rubyversed(@base).evaluate.in_rubyverse(@template)[*subscripts,
|
81
|
+
{}] = params
|
78
82
|
end
|
83
|
+
nil
|
79
84
|
end
|
80
85
|
|
81
86
|
end
|
87
|
+
|
88
|
+
# END
|