ltdtemplate 0.2.4 → 1.0.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.
- 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
|