musterb 0.0.3 → 0.0.4

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,7 @@
1
+ class Musterb::Chain
2
+ include ExtractValues
3
+
4
+ def initialize(value)
5
+ @context = new_context(value, Musterb::NullExtractor.new(nil))
6
+ end
7
+ end
@@ -1,18 +1,11 @@
1
1
  class Musterb::Evaluator
2
+ include ExtractValues
3
+
2
4
  def initialize(context)
3
5
  @context = context
4
- end
6
+ end
5
7
 
6
- def [](symbol)
7
- return @context.value if symbol == "."
8
- final_context = symbol.split(".").inject(@context) do |con, symbol|
9
- new_context con[symbol], con
10
- end
11
- final_context.value
12
- end
13
-
14
- def block(symbol)
15
- value = self[symbol]
8
+ def block_if(value)
16
9
  return if is_falsy? value
17
10
 
18
11
  case value
@@ -25,8 +18,8 @@ class Musterb::Evaluator
25
18
  end
26
19
  end
27
20
 
28
- def block_unless(symbol)
29
- yield if is_falsy? self[symbol]
21
+ def block_unless(value)
22
+ yield if is_falsy? value
30
23
  end
31
24
 
32
25
  private
@@ -40,26 +33,11 @@ class Musterb::Evaluator
40
33
  else
41
34
  !value
42
35
  end
43
- end
44
-
45
- def new_context(value, old_context = @context)
46
- case value
47
- when Hash
48
- Musterb::HashExtractor.new(value, old_context)
49
- when nil
50
- Musterb::NullExtractor.new(old_context)
51
- else
52
- Musterb::ObjectExtractor.new(value, old_context)
53
- end
54
- end
55
-
56
- def old_context
57
- @context.parent
58
- end
36
+ end
59
37
 
60
38
  def switch_context(value)
61
39
  @context = new_context(value)
62
40
  yield value
63
- @context = old_context
41
+ @context = @context.parent
64
42
  end
65
43
  end
@@ -0,0 +1,25 @@
1
+ module ExtractValues
2
+ def value
3
+ @context.value
4
+ end
5
+
6
+ def [](symbol)
7
+ @context[symbol]
8
+ end
9
+
10
+ def chain(symbol)
11
+ Musterb::Chain.new self[symbol]
12
+ end
13
+
14
+ private
15
+ def new_context(value, old_context = @context)
16
+ case value
17
+ when Hash
18
+ Musterb::HashExtractor.new(value, old_context)
19
+ when nil
20
+ Musterb::NullExtractor.new(old_context)
21
+ else
22
+ Musterb::ObjectExtractor.new(value, old_context)
23
+ end
24
+ end
25
+ end
@@ -3,24 +3,35 @@ class Musterb::Musterbifier
3
3
  @template = template
4
4
  end
5
5
 
6
+ def fetch(tokens)
7
+ tokens = tokens.strip.split(".")
8
+ last_token = tokens.pop
9
+ fetch_command = tokens.inject("musterb") do |str, token|
10
+ "#{str}.chain('#{token}')"
11
+ end
12
+ "#{fetch_command}['#{last_token}']"
13
+ end
14
+
6
15
  def to_erb
7
16
  @template.gsub(/\{\{(\{?[^\}]*\}?)\}\}/) do |match|
8
17
  match = $1
9
18
  case match[0]
10
19
  when '#'
11
- "<% musterb.block '#{match[1..-1].strip}' do %>"
20
+ "<% musterb.block_if #{fetch match[1..-1]} do %>"
12
21
  when '^'
13
- "<% musterb.block_unless '#{match[1..-1].strip}' do %>"
22
+ "<% musterb.block_unless #{fetch match[1..-1]} do %>"
14
23
  when "/"
15
24
  "<% end %>"
16
25
  when '{'
17
- "<%= musterb['#{match[1..-2].strip}'] %>"
26
+ "<%= #{fetch match[1..-2]} %>"
18
27
  when '&'
19
- "<%= musterb['#{match[1..-1].strip}'] %>"
28
+ "<%= #{fetch match[1..-1]} %>"
20
29
  when '!'
21
30
  ""
31
+ when '.'
32
+ "<%== musterb.current %>"
22
33
  else
23
- "<%== musterb['#{match.strip}'] %>"
34
+ "<%== #{fetch match} %>"
24
35
  end
25
36
  end
26
37
  end
@@ -1,3 +1,3 @@
1
1
  module Musterb
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/lib/musterb.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  require "musterb/version"
2
+ require "musterb/extract_values"
2
3
  require "musterb/musterbifier"
3
4
  require "musterb/binding_extractor"
4
5
  require "musterb/hash_extractor"
5
6
  require "musterb/object_extractor"
6
7
  require "musterb/null_extractor"
7
8
  require "musterb/evaluator"
9
+ require "musterb/chain"
8
10
 
9
11
  module Musterb
10
12
  def self.to_erb(template)
data/musterb.gemspec CHANGED
@@ -20,4 +20,5 @@ Gem::Specification.new do |gem|
20
20
  gem.add_dependency "erubis"
21
21
  gem.add_dependency "hashie"
22
22
  gem.add_development_dependency "rspec"
23
+ gem.add_development_dependency "mustache" # for performance
23
24
  end
@@ -7,74 +7,65 @@ describe Musterb::Evaluator do
7
7
 
8
8
  it "pulls out values from ." do
9
9
  evaluator = Musterb::Evaluator.new Musterb::ObjectExtractor.new(2, nil)
10
- evaluator["."].should eq 2
10
+ evaluator.value.should eq 2
11
11
  end
12
12
 
13
13
  it "can do nested values" do
14
14
  evaluator = Musterb::Evaluator.new Musterb::ObjectExtractor.new(2, nil)
15
- evaluator["next.to_s"].should eq "3"
15
+ evaluator.chain("next")["to_s"].should eq "3"
16
+ end
17
+
18
+ it "can deeply nest things" do
19
+ evaluator = Musterb::Evaluator.new Musterb::ObjectExtractor.new(2, nil)
20
+ evaluator.chain("next").chain("next")["to_s"].should eq "4"
16
21
  end
17
22
 
18
23
  it "does not barf when pulling out a value on nil" do
19
24
  evaluator = Musterb::Evaluator.new Musterb::HashExtractor.new({:foo => nil}, nil)
20
- evaluator["foo.bar"].should eq nil
25
+ evaluator.chain("foo")["bar"].should eq nil
21
26
  end
22
27
 
23
28
  context "block" do
24
- it "yields to the block if a value is set" do
25
- foo = "bar"
26
- evaluator = Musterb::Evaluator.new Musterb::BindingExtractor.new(binding)
27
- expect { |b| evaluator.block("foo", &b) }.to yield_control
29
+ let(:evaluator) { Musterb::Evaluator.new Musterb::NullExtractor.new(nil) }
30
+
31
+ it "yields to the block if a value is set" do
32
+ expect { |b| evaluator.block_if("bar", &b) }.to yield_control
28
33
  end
29
34
 
30
35
  it "does not yield to the block if the value is unset" do
31
- foo = nil
32
- evaluator = Musterb::Evaluator.new Musterb::BindingExtractor.new(binding)
33
- expect { |b| evaluator.block("foo", &b) }.not_to yield_control
36
+ expect { |b| evaluator.block_if(nil, &b) }.not_to yield_control
34
37
  end
35
38
 
36
39
  it "yields to the block for every element in the array" do
37
- foo = [1, 2, 3]
38
- evaluator = Musterb::Evaluator.new Musterb::BindingExtractor.new(binding)
39
- expect { |b| evaluator.block("foo", &b) }.to yield_successive_args(1,2,3)
40
+ expect { |b| evaluator.block_if([1,2,3], &b) }.to yield_successive_args(1,2,3)
40
41
  end
41
42
 
42
43
  it "does not yield to an empty array" do
43
- foo = []
44
- evaluator = Musterb::Evaluator.new Musterb::BindingExtractor.new(binding)
45
- expect { |b| evaluator.block("foo", &b) }.not_to yield_control
44
+ expect { |b| evaluator.block_if([], &b) }.not_to yield_control
46
45
  end
47
46
 
48
47
  it "yields to an empty hash" do
49
- foo = {}
50
- evaluator = Musterb::Evaluator.new Musterb::BindingExtractor.new(binding)
51
- expect { |b| evaluator.block("foo", &b) }.to yield_control
48
+ expect { |b| evaluator.block_if({}, &b) }.to yield_control
52
49
  end
53
50
  end
54
51
 
55
52
  context "block_unless" do
56
- it "does not yield to the block if a value is set" do
57
- foo = "bar"
58
- evaluator = Musterb::Evaluator.new Musterb::BindingExtractor.new(binding)
59
- expect { |b| evaluator.block_unless("foo", &b) }.not_to yield_control
53
+ let(:evaluator) { Musterb::Evaluator.new Musterb::NullExtractor.new(nil) }
54
+
55
+ it "does not yield to the block if a value is set" do
56
+ expect { |b| evaluator.block_unless("bar", &b) }.not_to yield_control
60
57
  end
61
58
 
62
59
  it "does not yield to the block if the value is unset" do
63
- foo = nil
64
- evaluator = Musterb::Evaluator.new Musterb::BindingExtractor.new(binding)
65
- expect { |b| evaluator.block_unless("foo", &b) }.to yield_control
60
+ expect { |b| evaluator.block_unless(nil, &b) }.to yield_control
66
61
  end
67
62
 
68
63
  it "yields to the block for every element in the array" do
69
- foo = [1, 2, 3]
70
- evaluator = Musterb::Evaluator.new Musterb::BindingExtractor.new(binding)
71
- expect { |b| evaluator.block_unless("foo", &b) }.not_to yield_control
64
+ expect { |b| evaluator.block_unless([1, 2, 3], &b) }.not_to yield_control
72
65
  end
73
66
 
74
- it "does not yield to an empty array" do
75
- foo = []
76
- evaluator = Musterb::Evaluator.new Musterb::BindingExtractor.new(binding)
77
- expect { |b| evaluator.block_unless("foo", &b) }.to yield_control
67
+ it "does not yield to an empty array" do
68
+ expect { |b| evaluator.block_unless([], &b) }.to yield_control
78
69
  end
79
70
  end
80
71
 
@@ -82,7 +73,7 @@ describe Musterb::Evaluator do
82
73
  it "switches inside a hash" do
83
74
  hash = { "foo" => "bar"}
84
75
  evaluator = Musterb::Evaluator.new Musterb::BindingExtractor.new(binding)
85
- evaluator.block "hash" do
76
+ evaluator.block_if hash do
86
77
  evaluator['foo'].should eq 'bar'
87
78
  end
88
79
  end
@@ -90,7 +81,7 @@ describe Musterb::Evaluator do
90
81
  it "resets the context later" do
91
82
  hash = { "foo" => "bar"}
92
83
  evaluator = Musterb::Evaluator.new Musterb::BindingExtractor.new(binding)
93
- evaluator.block("hash") {}
84
+ evaluator.block_if(hash) {}
94
85
  evaluator["hash"].should eq hash
95
86
  end
96
87
 
@@ -98,7 +89,7 @@ describe Musterb::Evaluator do
98
89
  foo = "bar"
99
90
  hash = { }
100
91
  evaluator = Musterb::Evaluator.new Musterb::BindingExtractor.new(binding)
101
- evaluator.block "hash" do
92
+ evaluator.block_if hash do
102
93
  evaluator['foo'].should eq 'bar'
103
94
  end
104
95
  end
@@ -16,14 +16,22 @@ describe Musterb::Musterbifier do
16
16
  end
17
17
 
18
18
  it "replaces blocks correctly" do
19
- Musterb::Musterbifier.new("{{#cond}}foo{{/cond}}").to_erb.should eq "<% musterb.block 'cond' do %>foo<% end %>"
19
+ Musterb::Musterbifier.new("{{#cond}}foo{{/cond}}").to_erb.should eq "<% musterb.block_if musterb['cond'] do %>foo<% end %>"
20
20
  end
21
21
 
22
22
  it "replaces carrot correctly" do
23
- Musterb::Musterbifier.new("{{^cond}}foo{{/cond}}").to_erb.should eq "<% musterb.block_unless 'cond' do %>foo<% end %>"
23
+ Musterb::Musterbifier.new("{{^cond}}foo{{/cond}}").to_erb.should eq "<% musterb.block_unless musterb['cond'] do %>foo<% end %>"
24
24
  end
25
25
 
26
26
  it "replaces comments with nothing" do
27
27
  Musterb::Musterbifier.new("{{! foo\n bar}}").to_erb.should eq ""
28
28
  end
29
+
30
+ it "replaces . with current value" do
31
+ Musterb::Musterbifier.new("{{.}}").to_erb.should eq "<%== musterb.current %>"
32
+ end
33
+
34
+ it "replaces foo.bar with a chain" do
35
+ Musterb::Musterbifier.new("{{foo.bar}}").to_erb.should eq "<%== musterb.chain('foo')['bar'] %>"
36
+ end
29
37
  end
@@ -0,0 +1,74 @@
1
+ require 'bundler/setup'
2
+ require 'benchmark'
3
+
4
+ require 'musterb'
5
+ require 'mustache'
6
+ require 'erubis'
7
+
8
+ template = <<-EOF
9
+ {{#products}}
10
+ <div class="product-item" data-variant-id='{{id}}' data-favorite-id='{{favorite_id}}' data-quick-view-url="{{quick_view_url}}">
11
+ <h3>Product: {{name}}</h3>
12
+
13
+ <a href="{{url}}" class="quickView">
14
+ <img src="{{thumbnail}}"/>
15
+ </a>
16
+ <ul>
17
+ <li>SKU: {{sku}}</li>
18
+ <li>Fabrics: {{fabrics}}</li>
19
+ <li>Themes: {{themes}}</li>
20
+ <li>Price: {{price}}</li>
21
+ <li>Designer: {{designer}}
22
+ <li class="favorite">
23
+ <div class="not-favorited {{favorited}}">
24
+ <button class="add-to-favorites">Add to Favorite</button>
25
+ </div>
26
+ <div class="favorited {{favorited}}">
27
+ <button class="remove-from-favorites">Remove from Favorite</button>
28
+ </div>
29
+ </li>
30
+ </ul>
31
+ </div>
32
+ {{/products}}
33
+ EOF
34
+
35
+ def random_product
36
+ {
37
+ "id" => rand(10000),
38
+ "favorite_id" => rand(10000),
39
+ "quick_view_url" => "http://foo.bar",
40
+ "name" => "Product name",
41
+ "url" => "http://foo.url",
42
+ "thumbnail" => "http://foo.image",
43
+ "sku" => "sku",
44
+ "fabrics" => "fabrics",
45
+ "themes" => "themes",
46
+ "designer" => "designer",
47
+ "favorited" => "favorited"
48
+ }
49
+ end
50
+
51
+ products = 16.times.map { random_product }
52
+
53
+ mustache = lambda { Mustache.render(template, :products => products) }
54
+
55
+ erb = Musterb.to_erb(template)
56
+ compiled_erb = Erubis::Eruby.new(erb)
57
+ musterb = lambda { compiled_erb.result(:products => products) }
58
+
59
+ if mustache.call == musterb.call
60
+ puts "mustache and musterb are identical"
61
+ else
62
+ puts "mustache and musterb differ (this will usually be whitespace)"
63
+ puts "mustache:"
64
+ puts mustache.call
65
+ puts "--------------------------------------------------------------------------------"
66
+ puts "musterb:"
67
+ puts musterb.call
68
+ puts "--------------------------------------------------------------------------------"
69
+ end
70
+
71
+ Benchmark.bmbm do |x|
72
+ x.report("mustache") { 1000.times { mustache.call } }
73
+ x.report("musterb") { 1000.times { musterb.call } }
74
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: musterb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -59,6 +59,22 @@ dependencies:
59
59
  - - ! '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: mustache
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
62
78
  description: The ability to compile mustache templates to erubis erb templates so
63
79
  that we can make use of the performance of compiling templates
64
80
  email:
@@ -83,8 +99,12 @@ files:
83
99
  bGliL211c3RlcmIucmI=
84
100
  - !binary |-
85
101
  bGliL211c3RlcmIvYmluZGluZ19leHRyYWN0b3IucmI=
102
+ - !binary |-
103
+ bGliL211c3RlcmIvY2hhaW4ucmI=
86
104
  - !binary |-
87
105
  bGliL211c3RlcmIvZXZhbHVhdG9yLnJi
106
+ - !binary |-
107
+ bGliL211c3RlcmIvZXh0cmFjdF92YWx1ZXMucmI=
88
108
  - !binary |-
89
109
  bGliL211c3RlcmIvaGFzaF9leHRyYWN0b3IucmI=
90
110
  - !binary |-
@@ -111,6 +131,8 @@ files:
111
131
  c3BlYy9tdXN0ZXJiL29iamVjdF9leHRyYWN0b3Jfc3BlYy5yYg==
112
132
  - !binary |-
113
133
  c3BlYy9tdXN0ZXJiX3NwZWMucmI=
134
+ - !binary |-
135
+ c3BlYy9wZXJmb3JtYW5jZS5yYg==
114
136
  - !binary |-
115
137
  c3BlYy9zcGVjX2hlbHBlci5yYg==
116
138
  homepage: ''
@@ -150,5 +172,7 @@ test_files:
150
172
  c3BlYy9tdXN0ZXJiL29iamVjdF9leHRyYWN0b3Jfc3BlYy5yYg==
151
173
  - !binary |-
152
174
  c3BlYy9tdXN0ZXJiX3NwZWMucmI=
175
+ - !binary |-
176
+ c3BlYy9wZXJmb3JtYW5jZS5yYg==
153
177
  - !binary |-
154
178
  c3BlYy9zcGVjX2hlbHBlci5yYg==