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,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "much-mixin"
4
+ require "nm/ext"
5
+ require "nm/render"
6
+ require "nm/source"
7
+
8
+ module Nm; end
9
+
10
+ module Nm::TemplateBehaviors
11
+ include MuchMixin
12
+
13
+ after_mixin_included do
14
+ attr_accessor :__nm_context__
15
+
16
+ alias_method :node, :__node__
17
+ alias_method :_node, :__node__
18
+ alias_method :n, :__node__
19
+
20
+ alias_method :map, :__map__
21
+ alias_method :_map, :__map__
22
+ alias_method :m, :__map__
23
+
24
+ alias_method :partial, :__partial__
25
+ alias_method :_partial, :__partial__
26
+ alias_method :p, :__partial__
27
+ end
28
+
29
+ mixin_instance_methods do
30
+ def __nm_render_stack__
31
+ @__nm_render_stack__ ||= []
32
+ end
33
+
34
+ def __nm_push_render__(locals)
35
+ __nm_render_stack__.push(
36
+ Nm::Render.new(dstack: @__nm_dstack__, locals: @__nm_locals__),
37
+ )
38
+ @__nm_dstack__ = [nil]
39
+ @__nm_locals__ = locals
40
+ end
41
+
42
+ def __nm_pop_render__
43
+ __nm_render_stack__.pop.tap do |render|
44
+ @__nm_dstack__ = render.dstack
45
+ @__nm_locals__ = render.locals
46
+ end
47
+ end
48
+
49
+ def __nm_data__
50
+ @__nm_dstack__.last || {}
51
+ end
52
+
53
+ def __node__(key, value = nil, &block)
54
+ unless @__nm_dstack__[-1].nil? || @__nm_dstack__[-1].is_a?(::Hash)
55
+ raise Nm::InvalidError, "invalid `node` call"
56
+ end
57
+ @__nm_dstack__[-1] ||= {}
58
+
59
+ @__nm_dstack__.push(nil)
60
+ instance_exec(&(block || Proc.new{}))
61
+ @__nm_dstack__.pop.tap{ |v| @__nm_dstack__[-1][key] = (v || value) }
62
+
63
+ self
64
+ end
65
+
66
+ def __map__(list, &block)
67
+ unless list.respond_to?(:map)
68
+ raise(
69
+ ArgumentError,
70
+ "given list (`#{list.class}`) doesn't respond to `.map`",
71
+ )
72
+ end
73
+ unless @__nm_dstack__[-1].nil? || @__nm_dstack__[-1].is_a?(::Array)
74
+ raise Nm::InvalidError, "invalid `map` call"
75
+ end
76
+ @__nm_dstack__[-1] ||= []
77
+
78
+ list.map do |item|
79
+ @__nm_dstack__.push(nil)
80
+ instance_exec(item, &(block || Proc.new{}))
81
+ @__nm_dstack__.pop.tap{ |v| @__nm_dstack__[-1].push(v || item) }
82
+ end
83
+
84
+ self
85
+ end
86
+
87
+ def __partial__(*args)
88
+ @__nm_dstack__[-1] =
89
+ @__nm_dstack__[-1].__nm_add_partial_data__(
90
+ __nm_context__.partial(*args),
91
+ )
92
+
93
+ self
94
+ end
95
+ end
96
+ end
data/lib/nm/version.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Nm
2
- VERSION = "0.5.4"
4
+ VERSION = "0.6.0"
3
5
  end
data/nm.gemspec CHANGED
@@ -1,5 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
- lib = File.expand_path('../lib', __FILE__)
2
+ # frozen_string_literal: true
3
+
4
+ lib = File.expand_path("../lib", __FILE__)
3
5
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
6
  require "nm/version"
5
7
 
@@ -8,12 +10,12 @@ Gem::Specification.new do |gem|
8
10
  gem.version = Nm::VERSION
9
11
  gem.authors = ["Kelly Redding", "Collin Redding"]
10
12
  gem.email = ["kelly@kellyredding.com", "collin.redding@me.com"]
11
- gem.summary = %q{Data templating system.}
12
- gem.description = %q{Data templating system.}
13
+ gem.summary = "Node-Map: a data templating DSL."
14
+ gem.description = "Node-Map: a data templating DSL."
13
15
  gem.homepage = "http://github.com/redding/nm"
14
- gem.license = 'MIT'
16
+ gem.license = "MIT"
15
17
 
16
- gem_files = `git ls-files`.split($/)
18
+ gem_files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
19
  gem_files -= gem_files.grep(%r{^(bench)/})
18
20
  gem_files -= gem_files.grep(%r{^(script)/})
19
21
  gem.files = gem_files
@@ -21,6 +23,10 @@ Gem::Specification.new do |gem|
21
23
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
22
24
  gem.require_paths = ["lib"]
23
25
 
24
- gem.add_development_dependency("assert", ["~> 2.16.1"])
26
+ gem.required_ruby_version = "~> 2.5"
27
+
28
+ gem.add_development_dependency("much-style-guide", ["~> 0.6.6"])
29
+ gem.add_development_dependency("assert", ["~> 2.19.6"])
25
30
 
31
+ gem.add_dependency("much-mixin", ["~> 0.2.4"])
26
32
  end
data/test/helper.rb CHANGED
@@ -1,24 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # this file is automatically required when you run `assert`
2
4
  # put any test helpers here
3
5
 
4
- require 'pathname'
6
+ require "pathname"
5
7
 
6
8
  # add the root dir to the load path
7
9
  ROOT = Pathname.new(File.expand_path("../..", __FILE__))
8
10
  $LOAD_PATH.unshift(ROOT.to_s)
9
11
 
10
- TEMPLATE_ROOT = ROOT.join('test/support/templates')
12
+ TEMPLATE_ROOT = ROOT.join("test/support/templates")
11
13
 
12
14
  # require pry for debugging (`binding.pry`)
13
- require 'pry'
14
-
15
- require 'test/support/factory'
16
-
17
- # 1.8.7 backfills
15
+ require "pry"
18
16
 
19
- # Array#sample
20
- if !(a = Array.new).respond_to?(:sample) && a.respond_to?(:choice)
21
- class Array
22
- alias_method :sample, :choice
23
- end
24
- end
17
+ require "test/support/factory"
@@ -1,4 +1,6 @@
1
- require 'assert/factory'
1
+ # frozen_string_literal: true
2
+
3
+ require "assert/factory"
2
4
 
3
5
  module Factory
4
6
  extend Assert::Factory
@@ -10,5 +12,4 @@ module Factory
10
12
  def self.template_file(name)
11
13
  TEMPLATE_ROOT.join(name).to_s
12
14
  end
13
-
14
15
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  map [1, 2, 3] do |num|
2
4
  node num.to_s, num
3
5
  end
@@ -1,3 +1,5 @@
1
- node 'locals' do
2
- node 'key', key
1
+ # frozen_string_literal: true
2
+
3
+ node "locals" do
4
+ node "key", key
3
5
  end
@@ -1,3 +1,5 @@
1
- node 'a', 'Aye'
2
- node 'b', 'Bee'
3
- node 'c', "See"
1
+ # frozen_string_literal: true
2
+
3
+ node "a", "Aye"
4
+ node "b", "Bee"
5
+ node "c", "See"
@@ -1,4 +1,9 @@
1
- _map (1..1) do
2
- n 'node local value', node
3
- _node 'map local value', map
1
+ # frozen_string_literal: true
2
+
3
+ _map(1..1) do
4
+ n "node local value", node
5
+ _node "map local value", map
6
+ __node__ "context method value", helper_method1
7
+ __node__ "context local value", key1
8
+ __node__ "render local value", key2
4
9
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  map [1, 2, 3] do |num|
2
4
  node num.to_s, num
3
5
  end
@@ -1,3 +1,5 @@
1
- node 'locals' do
2
- node 'key', key
1
+ # frozen_string_literal: true
2
+
3
+ node "locals" do
4
+ node "key", key
3
5
  end
@@ -1,3 +1,3 @@
1
- node 'locals' do
2
- node 'key', key
1
+ node "locals" do
2
+ node "key", key
3
3
  end
@@ -1,5 +1,7 @@
1
- node 'obj' do
2
- node 'a', 'Aye'
3
- node 'b', 'Bee'
4
- node 'c', "See"
1
+ # frozen_string_literal: true
2
+
3
+ node "obj" do
4
+ node "a", "Aye"
5
+ node "b", "Bee"
6
+ node "c", "See"
5
7
  end
data/test/system/.keep ADDED
File without changes
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "assert"
4
+ require "nm/context"
5
+
6
+ require "nm/source"
7
+ require "nm/template_behaviors"
8
+
9
+ class Nm::Context
10
+ class UnitTests < Assert::Context
11
+ desc "Nm::Context"
12
+ subject{ unit_class }
13
+
14
+ let(:unit_class){ Nm::Context }
15
+ end
16
+
17
+ class InitTests < UnitTests
18
+ desc "when init"
19
+ subject{ unit_class.new(context, source: source, locals: locals) }
20
+
21
+ let(:context){ Class.new.new }
22
+ let(:template_root){ Factory.template_root }
23
+ let(:source){ Nm::Source.new(template_root) }
24
+ let(:locals){ { "key" => "a-value" } }
25
+
26
+ should have_imeths :render, :partial, :render_content
27
+
28
+ should "setup the context to render Nm templates" do
29
+ local_name, local_val = [Factory.string, Factory.string]
30
+ nm_context =
31
+ unit_class.new(
32
+ context,
33
+ source: source,
34
+ locals: { local_name => local_val },
35
+ )
36
+
37
+ assert_that(context.class).does_not_include(Nm::TemplateBehaviors)
38
+
39
+ metaclass = class << context; self; end
40
+ assert_that(metaclass).includes(Nm::TemplateBehaviors)
41
+
42
+ assert_that(context).responds_to(local_name)
43
+ assert_that(context.send(local_name)).equals(local_val)
44
+
45
+ assert_that(context.__nm_context__).equals(nm_context)
46
+ end
47
+
48
+ # See test/unit/template_behaviors_tests.rb for testing the mixed in
49
+ # template behaviors and rendering.
50
+ end
51
+ end
@@ -1,94 +1,79 @@
1
- require 'assert'
2
- require 'nm/ext'
1
+ # frozen_string_literal: true
3
2
 
4
- module Nm::Ext
3
+ require "assert"
4
+ require "nm/ext"
5
5
 
6
+ module Nm::Ext
6
7
  class UnitTests < Assert::Context
7
8
  desc "Nm ruby extension"
8
9
  subject{ Nm }
9
10
 
10
- should "define and invalid runtime error" do
11
- assert_kind_of ::RuntimeError, subject::InvalidError.new
11
+ should "define an invalid runtime error" do
12
+ assert_that(subject::InvalidError.new).is_a(RuntimeError)
12
13
  end
13
-
14
14
  end
15
15
 
16
16
  class AddCallDataTests < UnitTests
17
- desc "__nm_add_call_data__"
18
- setup do
19
- @call_name = Factory.string
20
- end
17
+ desc "__nm_add_partial_data__"
21
18
 
22
19
  should "be added to ::Hash" do
23
- assert_responds_to :__nm_add_call_data__, ::Hash.new
20
+ assert_that({}).responds_to(:__nm_add_partial_data__)
24
21
  end
25
22
 
26
23
  should "be added to ::Array" do
27
- assert_responds_to :__nm_add_call_data__, ::Array.new
24
+ assert_that([]).responds_to(:__nm_add_partial_data__)
28
25
  end
29
26
 
30
27
  should "be added to nil" do
31
- assert_responds_to :__nm_add_call_data__, nil
28
+ assert_that(nil).responds_to(:__nm_add_partial_data__)
32
29
  end
33
-
34
30
  end
35
31
 
36
32
  class HashAddCallDataTests < AddCallDataTests
37
33
  desc "on ::Hash"
38
- setup do
39
- @h = { 1 => '1' }
40
- end
34
+
35
+ let(:h){ { 1 => "1" } }
41
36
 
42
37
  should "merge and return hash and nil data" do
43
- add = { 2 => '2' }
44
- assert_equal @h.merge(add), @h.__nm_add_call_data__(@call_name, add)
45
- assert_equal @h, @h.__nm_add_call_data__(@call_name, nil)
38
+ add = { 2 => "2" }
39
+ assert_that(h.__nm_add_partial_data__(add)).equals(h.merge(add))
40
+ assert_that(h.__nm_add_partial_data__(nil)).equals(h)
46
41
  end
47
42
 
48
43
  should "complain if adding Array data" do
49
44
  add = []
50
- assert_raises Nm::InvalidError do
51
- @h.__nm_add_call_data__(@call_name, add)
52
- end
45
+ assert_that{ h.__nm_add_partial_data__(add) }.raises(Nm::InvalidError)
53
46
  end
54
-
55
47
  end
56
48
 
57
49
  class ArrayAddCallDataTests < AddCallDataTests
58
50
  desc "on ::Array"
59
- setup do
60
- @a = [1, 2]
61
- end
51
+
52
+ let(:a){ [1, 2] }
62
53
 
63
54
  should "concat and return array and nil data" do
64
55
  add = [3, 4]
65
- assert_equal @a.concat(add), @a.__nm_add_call_data__(@call_name, add)
66
- assert_equal @a, @a.__nm_add_call_data__(@call_name, nil)
56
+ assert_that(a.__nm_add_partial_data__(add)).equals(a.concat(add))
57
+ assert_that(a.__nm_add_partial_data__(nil)).equals(a)
67
58
  end
68
59
 
69
60
  should "complain if adding Hash data" do
70
61
  add = {}
71
- assert_raises Nm::InvalidError do
72
- @a.__nm_add_call_data__(@call_name, add)
73
- end
62
+ assert_that{ a.__nm_add_partial_data__(add) }.raises(Nm::InvalidError)
74
63
  end
75
-
76
64
  end
77
65
 
78
66
  class NilAddCallDataTests < AddCallDataTests
79
67
  desc "on nil"
80
- setup do
81
- @n = nil
82
- end
68
+
69
+ let(:n){ nil }
83
70
 
84
71
  should "return any given data" do
85
- add_hash = { 1 => '1' }
72
+ add_hash = { 1 => "1" }
86
73
  add_array = [3, 4]
87
- assert_equal add_hash, @n.__nm_add_call_data__(@call_name, add_hash)
88
- assert_equal add_array, @n.__nm_add_call_data__(@call_name, add_array)
89
- assert_equal @n, @n.__nm_add_call_data__(@call_name, nil)
74
+ assert_that(n.__nm_add_partial_data__(add_hash)).equals(add_hash)
75
+ assert_that(n.__nm_add_partial_data__(add_array)).equals(add_array)
76
+ assert_that(n.__nm_add_partial_data__(nil)).equals(n)
90
77
  end
91
-
92
78
  end
93
-
94
79
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "assert"
4
+ require "nm"
5
+
6
+ module Nm
7
+ class UnitTests < Assert::Context
8
+ desc "Nm"
9
+ subject{ unit_class }
10
+
11
+ let(:unit_class){ Nm }
12
+
13
+ should have_imeths :default_context_class, :default_context
14
+
15
+ should "know its attributes" do
16
+ assert_that(subject.default_context_class).is_a(Class)
17
+ assert_that(subject.default_context).is_a(subject.default_context_class)
18
+ end
19
+ end
20
+ end