nm 0.5.4 → 0.6.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.
@@ -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