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
@@ -0,0 +1,27 @@
1
+ # LtdTemplate::Proxy::Nil - Represents nil in an LtdTemplate
2
+ #
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
+
7
+ require 'ltdtemplate/proxy'
8
+
9
+ class LtdTemplate::Proxy::Nil < LtdTemplate::Proxy
10
+
11
+ # Evaluate supported nil object methods.
12
+ def evaluate (opts = {})
13
+ case opts[:method]
14
+ when nil, 'call' then nil
15
+ when 'class' then 'Nil'
16
+ when 'type' then 'nil'
17
+ else super opts
18
+ end
19
+ end
20
+
21
+ # The template boolean value is false.
22
+ def tpl_boolean; false; end
23
+
24
+ # The template text for nil is the empty string.
25
+ def tpl_text; ''; end
26
+
27
+ end
@@ -0,0 +1,77 @@
1
+ # LtdTemplate::Proxy::Number - Proxy for a number in an LtdTemplate
2
+ #
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
+
7
+ require 'ltdtemplate/proxy'
8
+
9
+ class LtdTemplate::Proxy::Number < LtdTemplate::Proxy
10
+
11
+ # Evaluate supported methods for numeric objects.
12
+ def evaluate (opts = {})
13
+ case opts[:method]
14
+ when nil, 'call' then @original
15
+ when 'abs', 'ceil', 'floor'
16
+ @original.send opts[:method].to_sym
17
+ when 'class' then 'Number'
18
+ when 'flt', 'float' then @original.to_f
19
+ when 'int' then @original.to_i
20
+ when 'str', 'string' then @original.to_s
21
+ when 'type' then 'number'
22
+ when '+' then do_sequential(opts) { |a, b| a + b }
23
+ when '-' then do_subtract opts
24
+ when '*' then do_sequential(opts) { |a, b| a * b }
25
+ when '/' then do_sequential(opts) { |a, b| a / b }
26
+ when '%' then do_sequential(opts) { |a, b| a % b }
27
+ when '&' then do_sequential(opts) { |a, b| a & b }
28
+ when '|' then do_sequential(opts) { |a, b| a | b }
29
+ when '^' then do_sequential(opts) { |a, b| a ^ b }
30
+ when '<', '<=', '==', '!=', '>=', '>' then do_compare opts
31
+ else super opts
32
+ end
33
+ end
34
+
35
+ def tpl_text; @original.to_s; end
36
+
37
+ ##################################################
38
+
39
+ # Implement numeric comparison operators
40
+ def do_compare (opts)
41
+ if (params = opts[:parameters]) && params.size(:seq) > 0 &&
42
+ params[0].is_a?(Numeric)
43
+ diff = params[0]
44
+ else diff = 0
45
+ end
46
+ diff = @original - diff
47
+ case opts[:method]
48
+ when '<' then diff < 0
49
+ when '<=' then diff <= 0
50
+ when '==' then diff == 0
51
+ when '!=' then diff != 0
52
+ when '>=' then diff >= 0
53
+ when '>' then diff > 0
54
+ end
55
+ end
56
+
57
+ # Implement sequential operations (+, *, /, %, &, |, ^)
58
+ def do_sequential (opts = {}, &block)
59
+ if params = opts[:parameters]
60
+ params.values(:seq).select { |val| val.is_a? Numeric }.
61
+ inject(@original, &block)
62
+ else @original
63
+ end
64
+ end
65
+
66
+ # Implement "-" method (subtraction/negation)
67
+ def do_subtract (opts)
68
+ sum = @original
69
+ params = opts[:parameters]
70
+ if !params || params.size(:seq) == 0 then -@original
71
+ else do_sequential(opts) { |a, b| a - b }
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ # END
@@ -0,0 +1,74 @@
1
+ # LtdTemplate::Proxy::Regexp - Proxy for Regexp objects in an LtdTemplates
2
+ #
3
+ # @author Brian Katzung <briank@kappacs.com>, Kappa Computer Solutions, LLC
4
+ # @copyright 2014 Brian Katzung and Kappa Computer Solutions, LLC
5
+ # @license MIT License
6
+
7
+ require 'ltdtemplate/proxy'
8
+
9
+ class LtdTemplate::Proxy::Regexp < LtdTemplate::Proxy
10
+
11
+ # Evaluate supported methods on Regexp (regular expression) objects.
12
+ def evaluate (opts = {})
13
+ # These methods are supported regardless of whether regexp
14
+ # is enabled.
15
+ case opts[:method]
16
+ when nil, 'call'
17
+ if @template.options[:regexp] then return @original
18
+ else return nil
19
+ end
20
+ when 'class' then return 'Regexp'
21
+ when 'str', 'string'
22
+ return @original.to_s.tap do |str|
23
+ # RESOURCE string_total: Combined length of computed strings
24
+ @template.use :string_total, str.size
25
+ # RESOURCE string_length: Length of longest modified string
26
+ @template.using :string_length, str.size
27
+ end
28
+ when 'type' then return 'regexp'
29
+ end
30
+
31
+ # These methods are disabled unless regexp is enabled.
32
+ if @template.options[:regexp]
33
+ case opts[:method]
34
+ when 'ci', 'ignorecase'
35
+ if (@original.options & ::Regexp::IGNORECASE) != 0
36
+ return @original
37
+ else return ::Regexp.new(@original.source,
38
+ @original.options | ::Regexp::IGNORECASE)
39
+ end
40
+ when 'ext', 'extended'
41
+ if (@original.options & ::Regexp::EXTENDED) != 0
42
+ return @original
43
+ else return ::Regexp.new(@original.source,
44
+ @original.options | ::Regexp::EXTENDED)
45
+ end
46
+ when 'match' then return do_match opts
47
+ when 'multi', 'multiline'
48
+ if (@original.options & ::Regexp::MULTILINE) != 0
49
+ return @original
50
+ else return ::Regexp.new(@original.source,
51
+ @original.options | ::Regexp::MULTILINE)
52
+ end
53
+ end
54
+ end
55
+
56
+ super opts
57
+ end
58
+
59
+ def tpl_text; ''; end
60
+
61
+ ##################################################
62
+
63
+ def do_match (opts)
64
+ if (params = opts[:parameters]) && params.size(:seq) > 0 &&
65
+ params[0].is_a?(::String)
66
+ # Track array size generated??
67
+ @original.match(*params[0..1].values)
68
+ else nil
69
+ end
70
+ end
71
+
72
+ end
73
+
74
+ # END
@@ -0,0 +1,196 @@
1
+ # LtdTemplate::Proxy::String - Proxies a string in an LtdTemplate
2
+ #
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
+
7
+ require 'ltdtemplate/proxy'
8
+ require 'sarah'
9
+
10
+ class LtdTemplate::Proxy::String < LtdTemplate::Proxy
11
+
12
+ # Evaluate supported methods for strings.
13
+ def evaluate (opts = {})
14
+ case opts[:method]
15
+ when nil, 'call', 'str', 'string' then @original
16
+ when 'capcase' then meter @original.capitalize
17
+ when 'class' then 'String'
18
+ when 'downcase' then meter @original.downcase
19
+ when 'flt', 'float' then @original.to_f
20
+ when 'html'
21
+ require 'htmlentities'
22
+ meter(HTMLEntities.new(:html4).encode(@original, :basic,
23
+ :named, :decimal))
24
+ when 'idx', 'index', 'ridx', 'rindex' then do_index opts
25
+ when 'int' then @original.to_i
26
+ when 'join' then do_join opts
27
+ when 'len', 'length' then @original.length
28
+ when 'match' then do_match opts
29
+ when 'pcte'
30
+ meter(@original.gsub(/[^a-z0-9]/i) { |c| sprintf "%%%2x", c.ord })
31
+ when 'regexp'
32
+ if @template.options[:regexp] then ::Regexp.new @original
33
+ else nil
34
+ end
35
+ when 'rep', 'rep1', 'replace', 'replace1' then do_replace opts
36
+ when 'rng', 'range', 'slc', 'slice' then do_range_slice opts
37
+ when 'split' then do_split opts
38
+ when 'type' then 'string'
39
+ when 'upcase' then meter @original.upcase
40
+ when '+' then do_add opts
41
+ when '*' then do_multiply opts
42
+ when '<', '<=', '==', '!=', '>=', '>' then do_compare opts
43
+ else super opts
44
+ end
45
+ end
46
+
47
+ # Meter string resource usage
48
+ def meter (str)
49
+ # RESOURCE string_total: Combined length of computed strings
50
+ @template.use :string_total, str.size
51
+ # RESOURCE string_length: Length of longest modified string
52
+ @template.using :string_length, str.size
53
+ str
54
+ end
55
+
56
+ def tpl_text; @original; end
57
+
58
+ ##################################################
59
+
60
+ # "Add" (concatenate) strings
61
+ def do_add (opts)
62
+ combined = @original
63
+ if params = opts[:parameters]
64
+ params.each(:seq) do |key, val|
65
+ val = rubyversed(val).tpl_text
66
+ @template.using :string_length, (combined.length + val.length)
67
+ combined += val
68
+ end
69
+ end
70
+ meter combined
71
+ end
72
+
73
+ # Match a regular expression
74
+ def do_match (opts)
75
+ if (params = opts[:parameters]) && params.size(:seq) > 0 &&
76
+ params[0].is_a?(::Regexp)
77
+ params[0].in_rubyverse(@template).evaluate :method => 'match',
78
+ :parameters => Sarah[ @original, *params[1..-1].values ]
79
+ else nil
80
+ end
81
+ end
82
+
83
+ # "Multiply" (repeat) strings
84
+ def do_multiply (opts)
85
+ str = ''
86
+ if (params = opts[:parameters]) && params.size(:seq) > 0
87
+ times = params[0]
88
+ if times.is_a? Integer
89
+ str = @original
90
+ if times < 0
91
+ str = str.reverse
92
+ times = -times
93
+ end
94
+ @template.use :string_total, (str.length * times)
95
+ @template.using :string_length, (str.length * times)
96
+ str = str * times
97
+ end
98
+ end
99
+ meter str
100
+ end
101
+
102
+ # Implement string comparison operators
103
+ def do_compare (opts)
104
+ if (params = opts[:parameters]) && (params.size(:seq) > 0)
105
+ diff = rubyversed(params[0]).tpl_text
106
+ else
107
+ diff = ''
108
+ end
109
+
110
+ diff = @original <=> diff
111
+ case opts[:method]
112
+ when '<' then diff < 0
113
+ when '<=' then diff <= 0
114
+ when '==' then diff == 0
115
+ when '!=' then diff != 0
116
+ when '>=' then diff >= 0
117
+ when '>' then diff > 0
118
+ end
119
+ end
120
+
121
+ # Index and rindex
122
+ # str.index(substring[, offset])
123
+ # str.rindex(substring[, offset]
124
+ def do_index (opts)
125
+ substr, offset = '', nil
126
+ params = opts[:parameters]
127
+ if params && params.size(:seq) > 0
128
+ substr = rubyversed(params[0]).tpl_text
129
+ end
130
+ offset = params[1] if params && params.size(:seq) > 1
131
+ case opts[:method][0]
132
+ when 'r'
133
+ offset = -1 unless offset.is_a? Integer
134
+ @original.rindex(substr, offset) || -1
135
+ else
136
+ offset = 0 unless offset.is_a? Integer
137
+ @original.index(substr, offset) || -1
138
+ end
139
+ end
140
+
141
+ # String join
142
+ # str.join(list)
143
+ def do_join (opts)
144
+ params = opts[:parameters]
145
+ if params && params.size(:seq) > 0
146
+ meter(params.values(:seq).map { |val| rubyversed(val).tpl_text }.
147
+ join(@original))
148
+ else ''
149
+ end
150
+ end
151
+
152
+ # Range and slice:
153
+ # str.range([begin[, end]])
154
+ # str.slice([begin[, length]])
155
+ def do_range_slice (opts)
156
+ op1, op2 = 0, -1
157
+ params = opts[:parameters]
158
+ op1 = params[0] if params && params.size(:seq) > 0
159
+ op2 = params[1] if params && params.size(:seq) > 1
160
+ if opts[:method][0] == 'r' || op2 < 0
161
+ str = @original[op1..op2]
162
+ else str = @original[op1, op2]
163
+ end
164
+ meter(str || '')
165
+ end
166
+
167
+ # Replace and replace one
168
+ # str.replace(pattern, replacement)
169
+ # str.replace1(pattern, replacement)
170
+ def do_replace (opts)
171
+ if (params = opts[:parameters]) && params.size(:seq) > 1
172
+ pat, repl = params[0..1]
173
+ if opts[:method][-1] == '1'
174
+ # replace one
175
+ meter @original.sub(pat, repl)
176
+ else
177
+ # replace all
178
+ meter @original.gsub(pat, repl)
179
+ end
180
+ else @original
181
+ end
182
+ end
183
+
184
+ # Split
185
+ # str.split(pattern[, limit])
186
+ def do_split (opts)
187
+ if opts[:parameters]
188
+ params = opts[:parameters][0..1].values
189
+ else params = []
190
+ end
191
+ @original.split(*params).tap { |ary| ary.each { |str| meter str } }
192
+ end
193
+
194
+ end
195
+
196
+ # END
@@ -0,0 +1,94 @@
1
+ # LtdTemplate::Value - Common code for LtdTemplate value objects
2
+ #
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
+
7
+ require 'ltdtemplate'
8
+
9
+ module LtdTemplate::Value
10
+
11
+ class Code_Block; end
12
+
13
+ # Classes that include this module are their own method handlers
14
+ # and take the template as an initialization parameter.
15
+ include LtdTemplate::Method_Handler
16
+ def self.included (base); base.extend LtdTemplate::Consumer; end
17
+
18
+ # @!attribute [r] runtime_methods
19
+ # @return [Array<LtdTemplate::Value::Code_Block>]
20
+ # This object's run-time methods.
21
+ attr_reader :runtime_methods
22
+
23
+ # Initialize the object with a link to the associated template.
24
+ #
25
+ # @param template [LtdTemplate] The associated template object.
26
+ def initialize (template)
27
+ @template = template
28
+ @runtime_methods = {}
29
+ end
30
+
31
+ # Common operations for all values
32
+ def evaluate (opts = {})
33
+ case opts[:method]
34
+ when 'methods' then do_methods opts
35
+ else do_run_method opts
36
+ end
37
+ end
38
+
39
+ # Avoid "spilling our guts" when inspected
40
+ def inspect
41
+ "#<#{self.class.name}##{self.object_id} for #{@template.inspect}>"
42
+ end
43
+
44
+ # Shortcut to rubyversed in the template.
45
+ def rubyversed (obj); @template.rubyversed(obj); end
46
+
47
+ # Default boolean value is true
48
+ def tpl_boolean; true; end
49
+
50
+ ##################################################
51
+
52
+ # Set or get run-time methods.
53
+ #
54
+ # @param opts [Hash] A hash of method options.
55
+ # @return [nil]
56
+ def do_methods (opts)
57
+ if params = opts[:parameters]
58
+ params.values(:seq).each_slice(2) do |pair|
59
+ return @runtime_methods[pair[0]] if pair.size == 1
60
+ if pair[1].nil? then @runtime_methods.delete pair[0]
61
+ else @runtime_methods[pair[0]] = pair[1]
62
+ end
63
+ end
64
+ end
65
+ nil
66
+ end
67
+
68
+ # Try to execute run-time methods bound to the object or object
69
+ # class. Returns the return value from the code block or nil.
70
+ #
71
+ # @param opts [Hash] A hash of method options.
72
+ def do_run_method (opts)
73
+ method = nil
74
+ if name = opts[:method]
75
+ method = @runtime_methods[name]
76
+ class_name = self.evaluate :method => 'class'
77
+ if !method && class_name
78
+ class_var = @template.factory(:variable, class_name).evaluate
79
+ method = rubyversed(class_var).runtime_methods[name] if class_var
80
+ end
81
+ end
82
+ if method.is_a? LtdTemplate::Value::Code_Block
83
+ opts[:target] = self
84
+ rubyversed(method).evaluate opts
85
+ elsif !method.nil? then method
86
+ elsif mmproc = @template.options[:missing_method]
87
+ mmproc.call(@template, self, opts)
88
+ else nil
89
+ end
90
+ end
91
+
92
+ end
93
+
94
+ # END