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,34 @@
1
+ # For array/ or array% (similar to Ruby's *array)
2
+
3
+ require 'ltdtemplate'
4
+
5
+ module LtdTemplate::Value; end
6
+
7
+ class LtdTemplate::Value::Array_Splat
8
+
9
+ include LtdTemplate::Method_Handler
10
+
11
+ attr_reader :named, :positional
12
+
13
+ # @param positional [Array] Positional parameters
14
+ # @param named [Array] Flat array of key, value pairs
15
+ def initialize (positional, named = nil)
16
+ @positional, @named = positional, named
17
+ end
18
+
19
+ # Evaluate support array splat methods. Very little is supported,
20
+ # as these are only intended to be used in parameter and subscript
21
+ # list expansions.
22
+ def evaluate (opts = {})
23
+ case opts[:method]
24
+ when 'type' then 'array_splat'
25
+ else nil
26
+ end
27
+ end
28
+
29
+ # Unlike arrays, these generate no template text.
30
+ def tpl_text; ''; end
31
+
32
+ end
33
+
34
+ # END
@@ -1,17 +1,19 @@
1
- # LtdTemplate::Value::Code_Block - Represents an explicit code block in an
2
- # LtdTemplate
1
+ # LtdTemplate::Value::Code_Block - Represents an explicit code block
2
+ # in an LtdTemplate
3
3
  #
4
- # Explicit code blocks are wrappers around implied code blocks. They are
5
- # essentially anonymous functions; they accept optional parameters and
6
- # create a new namespace for the duration of each execution.
4
+ # Code blocks are wrappers around code sequences. They are essentially
5
+ # anonymous functions; they accept optional parameters and create a new
6
+ # namespace for the duration of each execution.
7
7
  #
8
8
  # @author Brian Katzung <briank@kappacs.com>, Kappa Computer Solutions, LLC
9
- # @copyright 2013 Brian Katzung and Kappa Computer Solutions, LLC
9
+ # @copyright 2013-2014 Brian Katzung and Kappa Computer Solutions, LLC
10
10
  # @license MIT License
11
11
 
12
- require 'ltdtemplate/code'
12
+ require 'ltdtemplate/value'
13
13
 
14
- class LtdTemplate::Value::Code_Block < LtdTemplate::Code
14
+ class LtdTemplate::Value::Code_Block
15
+
16
+ include LtdTemplate::Value
15
17
 
16
18
  attr_reader :code
17
19
 
@@ -20,24 +22,26 @@ class LtdTemplate::Value::Code_Block < LtdTemplate::Code
20
22
  @code = code
21
23
  end
22
24
 
23
- def to_boolean; true; end
24
- def to_native; self; end
25
- def to_text; ''; end
26
-
27
- def get_value (opts = {})
25
+ # Evaluate supported methods on code blocks. Most methods
26
+ # are passed to the code block.
27
+ def evaluate (opts = {})
28
28
  case opts[:method]
29
29
  when nil then self
30
- when 'type' then @template.factory :string, 'code'
30
+ when 'class' then 'Code'
31
+ when 'type' then 'code'
31
32
  else
32
33
  @template.push_namespace opts[:method], opts[:parameters],
33
34
  :target => (opts[:target] || self)
34
- result = @code.get_value
35
+ result = rubyversed(@code).evaluate
35
36
  @template.pop_namespace
36
37
  result
37
38
  end
38
39
  end
39
40
 
40
- # Type (for :missing_method callback)
41
- def type; :code_block; end
41
+ # In contrast to an implied code block, an uncalled explicit code
42
+ # block generates no template output.
43
+ def tpl_text; ''; end
42
44
 
43
45
  end
46
+
47
+ # END
@@ -1,150 +1,148 @@
1
1
  # LtdTemplate::Value::Namespace - Represents an LtdTemplate variable namespace
2
2
  #
3
3
  # @author Brian Katzung <briank@kappacs.com>, Kappa Computer Solutions, LLC
4
- # @copyright 2013 Brian Katzung and Kappa Computer Solutions, LLC
4
+ # @copyright 2013-2014 Brian Katzung and Kappa Computer Solutions, LLC
5
5
  # @license MIT License
6
6
 
7
- require 'ltdtemplate/value/array'
7
+ require 'sarah'
8
+ require 'xkeys'
9
+ require 'ltdtemplate/value'
8
10
 
9
- class LtdTemplate::Value::Namespace < LtdTemplate::Value::Array
11
+ class LtdTemplate::Value::Namespace < Sarah
10
12
 
11
- attr_reader :method, :parameters, :parent, :root
13
+ include LtdTemplate::Value
14
+ include XKeys::Hash
15
+
16
+ attr_reader :tpl_method, :parameters, :parent, :root, :template
12
17
  attr_accessor :target
13
18
 
14
- def initialize (template, method, parameters, parent = nil)
19
+ def initialize (template, tpl_method, parameters, parent = nil)
15
20
  super template
16
- @method, @parameters = method, parameters
21
+ @tpl_method, @parameters = tpl_method, parameters
17
22
  @root = parent ? parent.root : self
18
23
  @parent = parent
19
24
  @target = nil
20
- clear
25
+ clear()
21
26
  end
22
27
 
23
- def to_native
24
- if @sarah.rnd_size == 3 then native = []
25
- elsif @sarah.seq_size == 0 then native = {}
26
- else native = Sarah.new
27
- end
28
- @sarah.each do |key, value|
29
- # Exclude some permanent namespace attributes
30
- native[key] = value.to_native unless key =~ /^[_@$]$/
31
- end
32
- native
33
- end
34
-
35
- #
36
28
  # Clear values except for permanent namespace attributes.
37
- #
38
29
  def clear
39
30
  super
40
- @sarah.rnd['_'] = @parameters
41
- @sarah.rnd['@'] = @root
42
- @sarah.rnd['^'] = @parent if @parent
43
- @sarah.rnd['$'] = self
31
+ self['_'] = @parameters
32
+ self['@'] = @root
33
+ self['^'] = @parent if @parent
34
+ self['$'] = self
44
35
  self
45
36
  end
46
37
 
47
- #
38
+ # Evaluate supported methods on namespaces.
39
+ def evaluate (opts = {})
40
+ case opts[:method]
41
+ when nil, 'call' then self
42
+ when 'array', '*' # anonymous array
43
+ opts[:parameters] ? opts[:parameters] : @template.factory(:array)
44
+ when 'class' then 'Namespace'
45
+ when 'false' then false
46
+ when 'if' then do_if opts
47
+ when 'loop' then do_loop opts
48
+ when 'method' then @tpl_method
49
+ when 'nil' then nil
50
+ when 'target' then @target
51
+ when 'true' then true
52
+ when 'type' then 'namespace'
53
+ when 'use' then do_use opts
54
+ when 'var' then do_add_names opts
55
+ else super opts
56
+ end
57
+ end
58
+
48
59
  # Search for the specified item in the current namespace or above.
49
- #
50
60
  def find_item (name)
51
61
  namespace = self
52
62
  while namespace
53
- break if namespace.has_item? name
63
+ break if namespace.has_key? name
54
64
  namespace = namespace.parent
55
65
  end
56
66
  namespace
57
67
  end
58
68
 
59
- #
60
- # Template string-value for method
61
- #
62
- def method_string
63
- @method_string ||= @template.factory :string, @method
64
- end
69
+ # Namespaces do not generate template output.
70
+ def tpl_text; ''; end
65
71
 
66
- def get_value (opts = {})
67
- case opts[:method]
68
- when 'array', '*' # anonymous array
69
- opts[:parameters] ? opts[:parameters] :
70
- @template.factory(:parameters)
71
- when 'false' then @template.factory :boolean, false
72
- when 'if' then do_if opts
73
- when 'loop' then do_loop opts
74
- when 'method' then method_string
75
- when 'nil' then @template.nil
76
- when 'target' then @target || @template.nil
77
- when 'true' then @template.factory :boolean, true
78
- when 'use' then do_use opts
79
- when 'var' then do_add_names opts
80
- else super
81
- end
82
- end
72
+ # Auto-vivicate arrays in namespaces.
73
+ def xkeys_new (*args); @template.factory :array; end
83
74
 
84
- # Type (for :missing_method callback)
85
- def type; :namespace; end
75
+ ###################################################
86
76
 
87
- # Add new namespace names with nil or specific values
88
- #
77
+ # Add new namespace names with nil or specific values.
78
+ # $.var(name1, ..., nameN .. key1, val1, ..., keyN, valN)
89
79
  def do_add_names (opts)
90
- params = opts[:parameters]
91
- if params.positional.size
92
- tnil = @template.nil
93
- params.positional.each { |item| set_item(item.to_native, tnil) }
94
- end
95
- if params.named.size
96
- params.named.each { |item, val| set_item(item, val) }
80
+ if params = opts[:parameters]
81
+ params.each(:seq) { |idx, val| self[val] = nil }
82
+ params.each(:nsq) { |key, val| self[key] = val }
97
83
  end
98
- @template.nil
84
+ nil
99
85
  end
100
86
 
101
87
  # Implement conditionals
88
+ # $.if(\{test1}, \{result1}, ..., \{testN}, \{resultN}, \{else_value})
102
89
  def do_if (opts)
103
90
  if params = opts[:parameters]
104
- params.positional.each_slice(2) do |e1, e2|
105
- e1 = e1.get_value :method => 'call'
91
+ params.values(:seq).each_slice(2) do |pair|
92
+ e1 = rubyversed(pair[0]).evaluate :method => 'call'
106
93
 
107
94
  #
108
95
  # Return the "else" value, e1, in the absence of
109
96
  # a condition/result value pair.
110
97
  #
111
- return e1 unless e2
98
+ return e1 if pair.size == 1
112
99
 
113
100
  # Return the e2 result if e1 evaluates to true
114
- return e2.get_value(:method => 'call') if e1.to_boolean
101
+ if rubyversed(e1).tpl_boolean
102
+ return rubyversed(pair[1]).evaluate :method => 'call'
103
+ end
115
104
  end
116
105
  end
117
- @template.nil
106
+ nil
118
107
  end
119
108
 
109
+ # Implement loops
110
+ # $.loop(\{pre_test}, \{body})
111
+ # $.loop(\{pre_test}, \{body}, \{post_test})
120
112
  def do_loop (opts)
121
113
  results = @template.factory :array
122
- if params = opts[:parameters] and params.positional.size > 1
123
- params = params.positional
124
- while params[0].get_value(:method => 'call').to_boolean
114
+ if (params = opts[:parameters]) && params.size(:seq) > 1
115
+ while rubyversed(params[0]).evaluate(:method => 'call').
116
+ in_rubyverse(@template).tpl_boolean
117
+ # RESOURCE iterations: Total loop iterations
125
118
  @template.use :iterations
126
- results.sarah.push params[1].get_value(:method => 'call')
127
- break if params[2] and
128
- !params[2].get_value(:method => 'call').to_boolean
119
+ results.push rubyversed(params[1]).evaluate :method => 'call'
120
+ break if params.size(:seq) > 2 && !rubyversed(params[2]).
121
+ evaluate(:method => 'call').in_rubyverse(@template).
122
+ tpl_boolean
129
123
  end
130
124
  end
131
125
  results
132
126
  end
133
127
 
128
+ # Load external resources
134
129
  def do_use (opts)
135
130
  tpl = @template
136
- if loader = tpl.options[:loader] and
137
- params = opts[:parameters] and params.positional.size > 0
138
- name = params.positional[0].get_value.to_text
131
+ if (loader = tpl.options[:loader]) && (params = opts[:parameters]) &&
132
+ params.size(:seq) > 0
133
+ name = params[0]
139
134
  if !tpl.used[name]
135
+ # RESOURCE use: Total $.use invocations
140
136
  tpl.use :use
141
137
  tpl.used[name] = true
142
138
  result = loader.call(tpl, name)
143
- tpl.parse_template(tpl.get_tokens result).get_value if
139
+ tpl.parse_template(tpl.get_tokens result).evaluate if
144
140
  result.kind_of? String
145
141
  end
146
142
  end
147
- tpl.nil
143
+ nil
148
144
  end
149
145
 
150
146
  end
147
+
148
+ # END
data/ltdtemplate.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "ltdtemplate"
3
- s.version = "0.2.4"
4
- s.date = "2014-03-15"
3
+ s.version = "1.0.0"
4
+ s.date = "2014-05-20"
5
5
  s.authors = ["Brian Katzung"]
6
6
  s.email = ["briank@kappacs.com"]
7
7
  s.homepage = "http://rubygems.org/gems/ltdtemplate"
data/test/04number.rb CHANGED
@@ -7,13 +7,6 @@ class TestLtdTemplate_04 < MiniTest::Unit::TestCase
7
7
  @tpl = LtdTemplate.new
8
8
  end
9
9
 
10
- def test_imethods
11
- num = @tpl.factory :number
12
- [
13
- :get_value, :to_boolean, :to_native, :to_text
14
- ].each { |method| assert_respond_to num, method }
15
- end
16
-
17
10
  def test_basic
18
11
  @tpl.parse '<<1>>'
19
12
  assert_equal("1", @tpl.render, "literal")
data/test/05string.rb CHANGED
@@ -7,13 +7,6 @@ class TestLtdTemplate_05 < MiniTest::Unit::TestCase
7
7
  @tpl = LtdTemplate.new
8
8
  end
9
9
 
10
- def test_imethods
11
- num = @tpl.factory :string, ''
12
- [
13
- :get_value, :to_boolean, :to_native, :to_text
14
- ].each { |method| assert_respond_to num, method }
15
- end
16
-
17
10
  def test_basic
18
11
  @tpl.parse '<<"str">>'
19
12
  assert_equal("str", @tpl.render, "literal")
data/test/06array.rb CHANGED
@@ -7,15 +7,6 @@ class TestLtdTemplate_06 < MiniTest::Unit::TestCase
7
7
  @tpl = LtdTemplate.new
8
8
  end
9
9
 
10
- def test_imethods
11
- ary = @tpl.factory :array
12
- [
13
- :clear, :get_item, :get_value, :has_item?, :named, :positional,
14
- :scalar?, :set_from_array, :set_from_hash, :set_item, :set_value,
15
- :to_boolean, :to_native, :to_text
16
- ].each { |method| assert_respond_to ary, method }
17
- end
18
-
19
10
  def test_create
20
11
  @tpl.parse '<<a=a.type" "a.size>>'
21
12
  assert_equal 'array 0', @tpl.render
data/test/07each.rb CHANGED
@@ -10,7 +10,7 @@ class TestLtdTemplate_07 < MiniTest::Unit::TestCase
10
10
  def test_each
11
11
  @tpl.parse <<'TPL'
12
12
  <<a=(1,2,3..'four,4,'five,5,'six,6,7,7)
13
- a.each({ $.*($.method,$_[0].type,$_[0],$_[1]).join(",") }).join(";")
13
+ a.each({ $.*($.method,_[0].type,_[0],_[1]).join(",") }).join(";")
14
14
  .>>
15
15
  TPL
16
16
  expected = {}
@@ -31,7 +31,7 @@ TPL
31
31
  def test_each_rnd
32
32
  @tpl.parse <<'TPL'
33
33
  <<a=(1,2,3..'four,4,'five,5,'six,6,7,7)
34
- a.each_rnd({ $.*($.method,$_[0].type,$_[0],$_[1]).join(",") }).join(";")
34
+ a.each_rnd({ $.*($.method,_[0].type,_[0],_[1]).join(",") }).join(";")
35
35
  .>>
36
36
  TPL
37
37
  expected = {}
@@ -49,7 +49,7 @@ TPL
49
49
  def test_each_seq
50
50
  @tpl.parse <<'TPL'
51
51
  <<a=(1,2,3..'four,4,'five,5,'six,6,7,7)
52
- a.each_seq({ $.*($.method,$_[0].type,$_[0],$_[1]).join(",") }).join(";")
52
+ a.each_seq({ $.*($.method,_[0].type,_[0],_[1]).join(",") }).join(";")
53
53
  .>>
54
54
  TPL
55
55
  expected = {}
@@ -27,7 +27,7 @@ class TestLtdTemplate_08 < MiniTest::Unit::TestCase
27
27
  c=('c, 'c, 'x, 'c, 'y, 'c) d=(1, a/, 4, b/, 7, c%, 8 .. 'd, 'd, 'y, 'd) >>
28
28
  TPL
29
29
  @tpl.render
30
- d = @tpl.namespace.get_item(?d).to_native
30
+ d = @tpl.namespace[?d]
31
31
  assert_equal [1, 2, 3, 4, 5, 6, 7, 8], d.seq, "d (sequential)"
32
32
  assert_equal({ ?a => ?a, ?b => ?b, ?c => ?c, ?d => ?d,
33
33
  ?x => ?c, ?y => ?d }, d.rnd, "d (random-access)")
@@ -5,7 +5,7 @@ class TestLtdTemplate_10 < MiniTest::Unit::TestCase
5
5
 
6
6
  def test_missing_meth1
7
7
  miss_meth = Proc.new do |tpl, obj, opt|
8
- tpl.factory :string, "#{obj.type}.#{opt[:method]};"
8
+ "#{obj.evaluate :method => 'type'}.#{opt[:method]};"
9
9
  end
10
10
  tpl = LtdTemplate.new :missing_method => miss_meth
11
11
  tpl.parse "<<$.*.abc 1.def '.ghi>>"
data/test/11classes.rb CHANGED
@@ -1,17 +1,17 @@
1
1
  require 'minitest/autorun'
2
2
  require 'ltdtemplate'
3
- require 'ltdtemplate/value/nil'
3
+ require 'ltdtemplate/proxy/nil'
4
4
 
5
5
  class TestLtdTemplate_11 < MiniTest::Unit::TestCase
6
6
 
7
7
  def test_classes1
8
- LtdTemplate.set_classes :nil => Nil1
8
+ LtdTemplate.set_classes :nil_proxy => Nil1
9
9
  tpl = LtdTemplate.new
10
10
  tpl.parse '<<$.nil.type>>'
11
11
  assert_equal 'nil1', tpl.render, 'nil type after class class change'
12
12
 
13
13
  tpl = LtdTemplate.new
14
- tpl.set_classes :nil => Nil2
14
+ tpl.set_classes :nil_proxy => Nil2
15
15
  tpl.parse '<<$.nil.type>>'
16
16
  assert_equal 'nil2', tpl.render, 'nil type after instance class change'
17
17
 
@@ -22,22 +22,22 @@ class TestLtdTemplate_11 < MiniTest::Unit::TestCase
22
22
 
23
23
  end
24
24
 
25
- class Nil1 < LtdTemplate::Value::Nil
25
+ class Nil1 < LtdTemplate::Proxy::Nil
26
26
 
27
- def get_value (opts = {})
27
+ def evaluate (opts = {})
28
28
  case opts[:method]
29
- when 'type' then @template.factory :string, 'nil1'
29
+ when 'type' then 'nil1'
30
30
  else super
31
31
  end
32
32
  end
33
33
 
34
34
  end
35
35
 
36
- class Nil2 < LtdTemplate::Value::Nil
36
+ class Nil2 < LtdTemplate::Proxy::Nil
37
37
 
38
- def get_value (opts = {})
38
+ def evaluate (opts = {})
39
39
  case opts[:method]
40
- when 'type' then @template.factory :string, 'nil2'
40
+ when 'type' then 'nil2'
41
41
  else super
42
42
  end
43
43
  end