nm 0.5.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "assert"
4
+ require "nm/render"
5
+
6
+ class Nm::Render
7
+ class UnitTests < Assert::Context
8
+ desc "Nm::Render"
9
+ subject{ unit_class }
10
+
11
+ let(:unit_class){ Nm::Render }
12
+ end
13
+
14
+ class InitTests < UnitTests
15
+ desc "when init"
16
+ subject{ unit_class.new(dstack: dstack, locals: locals) }
17
+
18
+ let(:dstack){ [] }
19
+ let(:locals){ {} }
20
+
21
+ should have_readers :dstack, :locals
22
+
23
+ should "know its attributes" do
24
+ assert_that(subject.dstack).equals(dstack)
25
+ assert_that(subject.locals).equals(locals)
26
+ end
27
+ end
28
+ end
@@ -1,155 +1,138 @@
1
- require 'assert'
2
- require 'nm/source'
1
+ # frozen_string_literal: true
3
2
 
4
- require 'nm/template'
3
+ require "assert"
4
+ require "nm/source"
5
5
 
6
- class Nm::Source
6
+ require "nm/context"
7
7
 
8
+ class Nm::Source
8
9
  class UnitTests < Assert::Context
9
10
  desc "Nm::Source"
10
- setup do
11
- @source_class = Nm::Source
12
- end
13
- subject{ @source_class }
11
+ subject{ unit_class }
14
12
 
13
+ let(:unit_class){ Nm::Source }
15
14
  end
16
15
 
17
16
  class InitTests < UnitTests
18
17
  desc "when init"
19
- setup do
20
- @root = Factory.template_root
21
- @source = @source_class.new(@root)
22
- end
23
- subject{ @source }
18
+ subject{ source }
24
19
 
25
- should have_readers :root, :ext, :cache, :template_class
26
- should have_imeths :data, :render, :partial
20
+ let(:root){ Factory.template_root }
21
+ let(:source){ unit_class.new(root) }
27
22
 
28
- should "know its root" do
29
- assert_equal @root, subject.root.to_s
30
- end
31
-
32
- should "know its extension for looking up source files" do
33
- assert_nil subject.ext
23
+ should have_readers :root, :extension, :cache, :locals
24
+ should have_imeths :data, :render, :file_path!
34
25
 
35
- ext = Factory.string
36
- source = @source_class.new(@root, :ext => ext)
37
- assert_equal ".#{ext}", source.ext
38
- end
26
+ should "know its attributes" do
27
+ assert_that(subject.root.to_s).equals(root)
28
+ assert_that(subject.extension).is_nil
29
+ assert_that(subject.cache).is_a(unit_class::NullCache)
30
+ assert_that(subject.locals).equals({})
39
31
 
40
- should "not cache templates by default" do
41
- assert_kind_of NullCache, subject.cache
32
+ extension = Factory.string
33
+ locals = { key: "value" }
34
+ source =
35
+ unit_class.new(root, extension: extension, cache: true, locals: locals)
36
+ assert_that(source.extension).equals(".#{extension}")
37
+ assert_that(source.cache).is_a(Hash)
38
+ assert_that(source.locals).equals(locals)
42
39
  end
43
-
44
- should "cache templates if the :cache opt is `true`" do
45
- source = @source_class.new(@root, :cache => true)
46
- assert_kind_of Hash, source.cache
47
- end
48
-
49
- should "know its template class" do
50
- assert_true subject.template_class < Nm::Template
51
- end
52
-
53
- should "optionally take and apply default locals to its template class" do
54
- local_name, local_val = [Factory.string, Factory.string]
55
- source = @source_class.new(@root, :locals => {
56
- local_name => local_val
57
- })
58
- template = source.template_class.new
59
-
60
- assert_responds_to local_name, template
61
- assert_equal local_val, template.send(local_name)
62
- end
63
-
64
40
  end
65
41
 
66
42
  class DataTests < InitTests
67
43
  desc "`data` method"
68
- setup do
69
- @file_path = Factory.template_file('obj.nm')
70
- end
44
+
45
+ let(:file_path){ Factory.template_file("obj.nm") }
71
46
 
72
47
  should "read the contents of a given file path" do
73
- exp = File.read(@file_path)
74
- assert_equal exp, subject.data(@file_path)
48
+ assert_that(subject.data(file_path)).equals(File.read(file_path))
75
49
  end
76
50
 
77
51
  should "not cache template source by default" do
78
- assert_equal [], subject.cache.keys
52
+ assert_that(subject.cache.keys).equals([])
79
53
  end
80
54
 
81
55
  should "cache template source by file path if enabled" do
82
- source = @source_class.new(@root, :cache => true)
56
+ source = unit_class.new(root, cache: true)
83
57
 
84
- exp = File.read(@file_path)
85
- assert_equal exp, source.data(@file_path)
86
- assert_equal [@file_path], source.cache.keys
87
- assert_equal exp, source.cache[@file_path]
58
+ file_data = File.read(file_path)
59
+ assert_that(source.data(file_path)).equals(file_data)
60
+ assert_that(source.cache.keys).equals([file_path])
61
+ assert_that(source.cache[file_path]).equals(file_data)
88
62
  end
89
-
90
63
  end
91
64
 
92
65
  class RenderTests < InitTests
93
66
  desc "`render` method"
94
- setup do
95
- @template_name = ['locals', 'locals_alt'].sample
96
- @file_locals = { 'key' => 'a-value' }
97
- @file_path = Dir.glob("#{Factory.template_file(@template_name)}*").first
98
- end
99
-
100
- should "render a template for the given template name and return its data" do
101
- exp = Nm::Template.new(subject, @file_path, @file_locals).__data__
102
- assert_equal exp, subject.render(@template_name, @file_locals)
103
- end
104
-
105
- should "alias `render` as `partial`" do
106
- exp = subject.render(@template_name, @file_locals)
107
- assert_equal exp, subject.partial(@template_name, @file_locals)
108
- end
109
-
110
- should "only render templates with the matching ext if one is specified" do
111
- source = @source_class.new(@root, :ext => 'nm')
112
- file_path = Factory.template_file('locals.nm')
113
- exp = Nm::Template.new(source, file_path, @file_locals).__data__
114
- ['locals', 'locals.nm'].each do |name|
115
- assert_equal exp, source.render(name, @file_locals)
116
- end
117
67
 
118
- source = @source_class.new(@root, :ext => 'inem')
119
- file_path = Factory.template_file('locals_alt.data.inem')
120
- exp = Nm::Template.new(source, file_path, @file_locals).__data__
121
- ['locals', 'locals_alt', 'locals_alt.data', 'locals_alt.data.inem'].each do |name|
122
- assert_equal exp, source.render(name, @file_locals)
68
+ let(:custom_context){ Class.new.new }
69
+ let(:template_name){ ["locals", "locals_alt"].sample }
70
+ let(:file_path) do
71
+ Dir.glob("#{Factory.template_file(template_name)}*").first
72
+ end
73
+ let(:file_locals){ { "key" => "a-value" } }
74
+
75
+ should "render a template for the given name and return its data" do
76
+ assert_that(subject.render(template_name, locals: file_locals))
77
+ .equals(
78
+ Nm::Context
79
+ .new(Nm.default_context, source: subject, locals: subject.locals)
80
+ .render(template_name, file_locals),
81
+ )
82
+ end
83
+
84
+ should "only render templates with the matching extension if specified" do
85
+ source = unit_class.new(root, extension: "nm")
86
+ ["locals", "locals.nm"].each do |name|
87
+ assert_that(subject.render(name, locals: file_locals))
88
+ .equals(
89
+ Nm::Context
90
+ .new(Nm.default_context, source: subject, locals: subject.locals)
91
+ .render(name, file_locals),
92
+ )
123
93
  end
124
94
 
125
- source = @source_class.new(@root, :ext => 'nm')
126
- ['locals_alt', 'locals_alt.data', 'locals_alt.data.inem'].each do |name|
127
- assert_raises(ArgumentError){ source.render(name, @file_locals) }
95
+ source = unit_class.new(root, extension: "inem")
96
+ ["locals", "locals_alt", "locals_alt.data", "locals_alt.data.inem"]
97
+ .each do |name|
98
+ assert_that(subject.render(name, locals: file_locals))
99
+ .equals(
100
+ Nm::Context
101
+ .new(
102
+ Nm.default_context,
103
+ source: subject,
104
+ locals: subject.locals,
105
+ )
106
+ .render(name, file_locals),
107
+ )
108
+ end
109
+
110
+ source = unit_class.new(root, extension: "nm")
111
+ ["locals_alt", "locals_alt.data", "locals_alt.data.inem"].each do |name|
112
+ assert_that{ source.render(name, file_locals) }.raises(ArgumentError)
128
113
  end
129
114
 
130
- source = @source_class.new(@root, :ext => 'data')
131
- ['locals_alt', 'locals_alt.data', 'locals_alt.data.inem'].each do |name|
132
- assert_raises(ArgumentError){ source.render(name, @file_locals) }
115
+ source = unit_class.new(root, extension: "data")
116
+ ["locals_alt", "locals_alt.data", "locals_alt.data.inem"].each do |name|
117
+ assert_that{ source.render(name, file_locals) }.raises(ArgumentError)
133
118
  end
134
119
  end
135
-
136
120
  end
137
121
 
138
- class DefaultSource < UnitTests
139
- desc "DefaultSource"
140
- setup do
141
- @source = Nm::DefaultSource.new
142
- end
143
- subject{ @source }
122
+ class FilePathBangTests < InitTests
123
+ desc "`file_path!` method"
144
124
 
145
- should "be a Source" do
146
- assert_kind_of @source_class, subject
125
+ let(:template_name){ ["locals", "locals_alt"].sample }
126
+ let(:file_path) do
127
+ Dir.glob("#{Factory.template_file(template_name)}*").first
147
128
  end
148
129
 
149
- should "use `/` as its root" do
150
- assert_equal '/', subject.root.to_s
130
+ should "return the file path for the given template name if it exists" do
131
+ assert_that(subject.file_path!(template_name)).equals(file_path)
151
132
  end
152
133
 
134
+ should "complain if the given template name does not exist" do
135
+ assert_that{ subject.file_path!(Factory.path) }.raises(ArgumentError)
136
+ end
153
137
  end
154
-
155
138
  end
@@ -0,0 +1,259 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "assert"
4
+ require "nm/template_behaviors"
5
+
6
+ require "nm/context"
7
+ require "nm/ext"
8
+ require "nm/source"
9
+
10
+ module Nm::TemplateBehaviors
11
+ class UnitTests < Assert::Context
12
+ desc "Nm::TemplateBehaviors"
13
+ subject{ unit_class }
14
+
15
+ let(:unit_module){ Nm::TemplateBehaviors }
16
+ end
17
+
18
+ class InitTests < UnitTests
19
+ desc "when mixed in on an context instance"
20
+ subject{ context }
21
+
22
+ setup do
23
+ nm_context
24
+ context.__nm_push_render__({})
25
+ end
26
+
27
+ let(:nm_context) do
28
+ Nm::Context.new(context, source: source, locals: context_locals)
29
+ end
30
+ let(:context){ Class.new.new }
31
+ let(:template_root){ Factory.template_root }
32
+ let(:source){ Nm::Source.new(template_root) }
33
+ let(:context_locals){ {} }
34
+
35
+ should have_accessors :__nm_context__
36
+ should have_imeths :__nm_data__, :__node__, :__map__, :__partial__
37
+ should have_imeths :node, :_node, :n
38
+ should have_imeths :map, :_map, :m
39
+ should have_imeths :partial, :_partial, :p
40
+
41
+ should "have empty data if no markup meths called or no source given" do
42
+ assert_that(subject.__nm_data__).equals({})
43
+ end
44
+ end
45
+
46
+ class NodeMethodTests < InitTests
47
+ desc "the `__node__` method"
48
+
49
+ should "return itself when called" do
50
+ assert_that(subject.__node__("key", "value")).equals(subject)
51
+ end
52
+
53
+ should "add key-value pairs at the root level" do
54
+ subject.__node__("a", "Aye")
55
+ assert_that(subject.__nm_data__).equals({ "a" => "Aye" })
56
+ end
57
+
58
+ should "add key-value pairs at nested levels" do
59
+ subject.__node__("nested"){ __node__("a", "Aye") }
60
+ assert_that(subject.__nm_data__)
61
+ .equals({
62
+ "nested" => { "a" => "Aye" },
63
+ })
64
+ end
65
+
66
+ should "be aliased as `node`, `_node` and `n`" do
67
+ exp = { "a" => "Aye" }
68
+ assert_that(subject.__node__("a", "Aye").__nm_data__).equals(exp)
69
+ assert_that(subject.node("a", "Aye").__nm_data__).equals(exp)
70
+ assert_that(subject._node("a", "Aye").__nm_data__).equals(exp)
71
+ assert_that(subject.n("a", "Aye").__nm_data__).equals(exp)
72
+ end
73
+
74
+ should "complain if called after a `__map__` call" do
75
+ subject.__map__([1, 2, 3])
76
+ assert_that{ subject.__node__("a", "Aye") }.raises(Nm::InvalidError)
77
+ end
78
+ end
79
+
80
+ class MapMethodTests < InitTests
81
+ desc "the `map` method"
82
+
83
+ let(:list){ [1, 2, 3] }
84
+
85
+ should "return itself when called" do
86
+ assert_that(subject.__map__([], &Proc.new{})).equals(subject)
87
+ end
88
+
89
+ should "map a given list to the data" do
90
+ assert_that(subject.__map__(list).__nm_data__).equals(list)
91
+ end
92
+
93
+ should "map a given list to node data" do
94
+ subject.__map__(list){ |item| __node__(item.to_s, item) }
95
+ assert_that(subject.__nm_data__)
96
+ .equals(
97
+ [
98
+ { "1" => 1 },
99
+ { "2" => 2 },
100
+ { "3" => 3 },
101
+ ],
102
+ )
103
+ end
104
+
105
+ should "map a given list to node data at a nested level" do
106
+ list_value = list
107
+ subject.__node__("list") do
108
+ __map__(list_value){ |item| __node__(item.to_s, item) }
109
+ end
110
+ assert_that(subject.__nm_data__)
111
+ .equals(
112
+ {
113
+ "list" => [
114
+ { "1" => 1 },
115
+ { "2" => 2 },
116
+ { "3" => 3 },
117
+ ],
118
+ },
119
+ )
120
+ end
121
+
122
+ should "be aliased as `map`, `_map` and `m`" do
123
+ assert_that(subject.__map__(list).__nm_data__).equals(list)
124
+ assert_that(subject.map(list).__nm_data__).equals(list + list)
125
+ assert_that(subject._map(list).__nm_data__).equals(list + list + list)
126
+ assert_that(subject.m(list).__nm_data__).equals(list + list + list + list)
127
+ end
128
+
129
+ should "complain if given a list that doesn't respond to `.map`" do
130
+ val = 123
131
+ assert_that(val).does_not_respond_to(:map)
132
+ assert_that{ subject.__map__(val) }.raises(ArgumentError)
133
+ end
134
+
135
+ should "complain if called after a `__node__` call" do
136
+ subject.__node__("a", "Aye")
137
+ assert_that{ subject.__map__([1, 2, 3]) }.raises(Nm::InvalidError)
138
+ end
139
+ end
140
+
141
+ class PartialMethodTests < InitTests
142
+ desc "the `partial` method"
143
+
144
+ let(:obj_template_name){ "obj" }
145
+ let(:obj) do
146
+ {
147
+ "obj" => {
148
+ "a" => "Aye",
149
+ "b" => "Bee",
150
+ "c" => "See",
151
+ },
152
+ }
153
+ end
154
+ let(:list_template_name){ "list" }
155
+ let(:list) do
156
+ [
157
+ { "1" => 1 },
158
+ { "2" => 2 },
159
+ { "3" => 3 },
160
+ ]
161
+ end
162
+ let(:partial_obj_template_name){ "_obj" }
163
+ let(:partial_obj) do
164
+ {
165
+ "a" => "Aye",
166
+ "b" => "Bee",
167
+ "c" => "See",
168
+ }
169
+ end
170
+ let(:partial_list_template_name){ "_list" }
171
+ let(:partial_list){ list }
172
+
173
+ should "return itself when called" do
174
+ assert_that(subject.__partial__(Factory.template_file("obj")))
175
+ .equals(subject)
176
+ end
177
+
178
+ should "render a template for the given partial name and add its data" do
179
+ assert_that(subject.__partial__(partial_obj_template_name).__nm_data__)
180
+ .equals(partial_obj)
181
+ end
182
+
183
+ should "be aliased as `render`, `_render` and `r`" do
184
+ assert_that(subject.__partial__(partial_obj_template_name).__nm_data__)
185
+ .equals(partial_obj)
186
+ assert_that(subject.partial(partial_obj_template_name).__nm_data__)
187
+ .equals(partial_obj)
188
+ assert_that(subject._partial(partial_obj_template_name).__nm_data__)
189
+ .equals(partial_obj)
190
+ assert_that(subject.p(partial_obj_template_name).__nm_data__)
191
+ .equals(partial_obj)
192
+ end
193
+
194
+ should "merge if call returns an obj and called after `__node__`" do
195
+ subject.__node__("1", "One")
196
+
197
+ exp = { "1" => "One" }.merge(partial_obj)
198
+ assert_that(subject.__partial__(partial_obj_template_name).__nm_data__)
199
+ .equals(exp)
200
+ end
201
+
202
+ should "complain if call returns an obj and called after `__map__`" do
203
+ subject.__map__([1, 2, 3])
204
+ assert_that{ subject.__partial__(partial_obj_template_name).__nm_data__ }
205
+ .raises(Nm::InvalidError)
206
+ end
207
+
208
+ should "merge if call returns a list and called after `__map__`" do
209
+ subject.__map__([1, 2, 3])
210
+
211
+ exp = [1, 2, 3].concat(partial_list)
212
+ assert_that(subject.__partial__(partial_list_template_name).__nm_data__)
213
+ .equals(exp)
214
+ end
215
+
216
+ should "complain if call returns a list and called after `__node__`" do
217
+ subject.__node__("1", "One")
218
+
219
+ assert_that{ subject.__partial__(partial_list_template_name).__nm_data__ }
220
+ .raises(Nm::InvalidError)
221
+ end
222
+ end
223
+
224
+ class RenderTests < InitTests
225
+ desc "and used to render a template"
226
+
227
+ let(:context) do
228
+ Class
229
+ .new{
230
+ def helper_method1
231
+ "helper method value 1"
232
+ end
233
+ }
234
+ .new
235
+ end
236
+ let(:context_locals) do
237
+ {
238
+ "key1" => "value1",
239
+ "node" => "A Node",
240
+ "map" => "A Map",
241
+ }
242
+ end
243
+ let(:render_locals) do
244
+ { "key2" => "value2" }
245
+ end
246
+
247
+ should "render exposing locals and context methods as expected" do
248
+ d = nm_context.render("aliases.nm", render_locals)
249
+ assert_that(d).is_a(::Array)
250
+ assert_that(d.size).equals(1)
251
+ assert_that(d.first["node local value"]).equals("A Node")
252
+ assert_that(d.first["map local value"]).equals("A Map")
253
+ assert_that(d.first["context method value"])
254
+ .equals("helper method value 1")
255
+ assert_that(d.first["context local value"]).equals("value1")
256
+ assert_that(d.first["render local value"]).equals("value2")
257
+ end
258
+ end
259
+ end