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
@@ -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