musterb 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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==