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.
Files changed (40) hide show
  1. data/CHANGELOG +10 -1
  2. data/Gemfile +2 -1
  3. data/RESOURCES +18 -32
  4. data/TEMPLATE_MANUAL.html +126 -47
  5. data/lib/ltdtemplate.rb +352 -242
  6. data/lib/ltdtemplate/code.rb +14 -87
  7. data/lib/ltdtemplate/code/call.rb +20 -16
  8. data/lib/ltdtemplate/code/parameters.rb +28 -31
  9. data/lib/ltdtemplate/code/sequence.rb +39 -0
  10. data/lib/ltdtemplate/code/subscript.rb +57 -50
  11. data/lib/ltdtemplate/code/variable.rb +22 -39
  12. data/lib/ltdtemplate/proxy.rb +26 -0
  13. data/lib/ltdtemplate/proxy/array.rb +258 -0
  14. data/lib/ltdtemplate/proxy/boolean.rb +74 -0
  15. data/lib/ltdtemplate/proxy/match.rb +40 -0
  16. data/lib/ltdtemplate/proxy/nil.rb +27 -0
  17. data/lib/ltdtemplate/proxy/number.rb +77 -0
  18. data/lib/ltdtemplate/proxy/regexp.rb +74 -0
  19. data/lib/ltdtemplate/proxy/string.rb +196 -0
  20. data/lib/ltdtemplate/value.rb +94 -0
  21. data/lib/ltdtemplate/value/array_splat.rb +34 -0
  22. data/lib/ltdtemplate/value/code_block.rb +21 -17
  23. data/lib/ltdtemplate/value/namespace.rb +77 -79
  24. data/ltdtemplate.gemspec +2 -2
  25. data/test/04number.rb +0 -7
  26. data/test/05string.rb +0 -7
  27. data/test/06array.rb +0 -9
  28. data/test/07each.rb +3 -3
  29. data/test/08interpolate.rb +1 -1
  30. data/test/10missing_meth.rb +1 -1
  31. data/test/11classes.rb +9 -9
  32. metadata +15 -13
  33. data/lib/ltdtemplate/code/code_block.rb +0 -30
  34. data/lib/ltdtemplate/value/array.rb +0 -210
  35. data/lib/ltdtemplate/value/boolean.rb +0 -82
  36. data/lib/ltdtemplate/value/nil.rb +0 -30
  37. data/lib/ltdtemplate/value/number.rb +0 -96
  38. data/lib/ltdtemplate/value/string.rb +0 -215
  39. data/lib/test.rb +0 -10
  40. data/test/03tpl_singletons.rb +0 -48
@@ -1,103 +1,30 @@
1
- # LtdTemplate::Code - Base class for LtdTemplate code/value objects
1
+ # LtdTemplate::Code - Base class for LtdTemplate code objects
2
2
  #
3
- # @author Brian Katzung <briank@kappacs.com>, Kappa Computer Solutions, LLC
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
- class LtdTemplate; end
7
+ require 'ltdtemplate'
8
8
 
9
9
  class LtdTemplate::Code
10
10
 
11
- # @!attribute [r] tpl_methods
12
- # @return [Array<LtdTemplate::Value::Code_Block>]
13
- # The code blocks bound to non-array values.
14
- attr_reader :tpl_methods
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
- # Set a non-array value's method code block.
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
- # Try to execute code-block methods bound to the object or object
78
- # class. Returns the return value from the code block or t-nil.
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
- # This is the parent namespace for value code classes.
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
- # Author:: Brian Katzung <briank@kappacs.com>, Kappa Computer Solutions, LLC
4
- # Copyright:: 2013 Brian Katzung and Kappa Computer Solutions, LLC
5
- # License:: MIT License
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 [LtdTemplate::Code] The target object
15
- # @param method [String] The method to call
16
- # @param parameters [LtdTemplate::Code::Parameters] The call 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 get_value (opts = {})
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
- result = @target.get_value({ :method => @method,
32
- :parameters => @parameters.get_value })
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
- opts[:method] ? result.get_value(opts) : result
38
- end
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
- # Pass has/get/set_item calls through to result of call;
41
- # in some cases it might be the same value each time.
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 array t-value.
26
+ # and return a corresponding Sarah.
27
27
  #
28
- def get_value (opts = {})
29
- named = {}
28
+ # @return [Sarah]
29
+ def evaluate (opts = {})
30
+ params = @template.factory :array
30
31
 
31
32
  # Process the positional parameters (pos1, ..., posN)
32
- positional = @positional.map do |code|
33
- val = code.get_value
34
- if val.is_a? LtdTemplate::Code::Parameters
35
- if val.named.is_a? Hash
36
- # Named parameters from array/
37
- val.named.each { |key, val| named[key] = val }
38
- elsif val.named.is_a? Array
39
- # Named parameters from array%
40
- val.named.each_slice(2) do |key, val|
41
- named[key.get_value.to_native] = val if val
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
- val.positional # Positional parameters from array/
45
- else val
44
+ else params.push value
46
45
  end
47
- end.flatten
46
+ end
48
47
 
49
48
  # Process the named parameters (.. key1, val1, ..., keyN, valN)
50
49
  if @named
51
- if @named.is_a? Hash then named.merge! @named
52
- else
53
- @named.each_slice(2) do |key, val|
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
- array = @template.factory(:array).set_value(positional, named, scalar)
56
+ # Is this a candidate for scalar assignment?
57
+ params.extend LtdTemplate::Univalue if
58
+ !@named && params.size(:seq) == 1
63
59
 
64
- # Parameters may get called if chained, e.g. array/.type
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
- # Author:: Brian Katzung <briank@kappacs.com>, Kappa Computer Solutions, LLC
5
- # Copyright:: 2013 Brian Katzung and Kappa Computer Solutions, LLC
6
- # License:: MIT License
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
- # Return native subscripts calculated from the supplied code blocks.
19
+ # Evaluate the target's value.
19
20
  #
20
- def native_subs (usage = false)
21
- nsubs = @subscripts ?
22
- @subscripts.map { |sub| sub.get_value.to_native }.flatten : []
23
- num_subs = nsubs.size
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 the target value, variable[sub1, ..., subN]
29
+ # Return subscripts calculated from the supplied code blocks.
33
30
  #
34
- def target (usage = false)
35
- current = @base.get_value
36
- native_subs(usage).each { |subs| current = current.get_item subs }
37
- current
38
- end
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
- # Implement the subscript interface for the target.
42
- #
43
- def has_item? (key); target.has_item? key; end
44
- def get_item (key); target.get_item key; end
45
- def set_item (key, value); target(true).set_item key, value; end
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
- # Set the target's value.
57
+ # Return the target value, variable[sub1, ..., subN]
49
58
  #
50
- def set_value (value)
51
- subs = native_subs true
52
- if subs.size == 0
53
- # If there are no subscripts, just use the base.
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
- def get_value (opts = {})
75
- case opts[:method]
76
- when '=' then do_set opts # see LtdTemplate::Code
77
- else target.get_value opts
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