ltdtemplate 0.2.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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