mustache 1.0.0 → 1.0.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a9a22c993556413f34a18b5f74023dbf1dfbdd92
4
- data.tar.gz: 28b5ac5ef50228c3bc860762c6a70e546022dd3d
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ N2MzZDViZWQ0ODY5NmZhYzc2NjdmZThkNWYzOWUxMjg1NDMzOWUwMw==
5
+ data.tar.gz: !binary |-
6
+ ZTY0MmE3MmU4M2RkM2RmNjg5N2Q5ZjBiNWRlZTZiN2UxY2ZhM2U0Zg==
5
7
  SHA512:
6
- metadata.gz: 0dcaecf69cf26d4a540f5e47d862b5bb318114e74f9885a03f180c510ed5fcff53d91ba56d8a97bd6b45fa8e1272c761230f9fb71c76fca8dd3332a0e1a8e900
7
- data.tar.gz: b1bb13fd0e318e55aa037616b86629a00fa3a2b54b350b93d4df738d9de816e9e145804da3519c145c49c2db142a5ff748b24c661d7133565da0ad3683d4c946
8
+ metadata.gz: !binary |-
9
+ YjYyMTdmOTgwMTQ3NGE3MjU1MGI3Nzg4Yzg2Mjk1YTJhY2UzNDZhNjVlMDBi
10
+ MmZiYTJjYzZmOTA4ZmEyN2VhNDAyNjA5ZmZkM2I4YWUyMGI5ZDQ5ZWVhMWRh
11
+ ODk3YTk0NDBhYzZkOGYyZDlhMjA1ODA2NWJmYmFlNjA3MTE2YzQ=
12
+ data.tar.gz: !binary |-
13
+ MGM4M2U2NDI4ZjRkZTU4ZTIzOTQwZjQ4MmMzZmE4NDczNDI4NTY2YzE3ZmNk
14
+ NDIzMWJlOWE5NDVmMzUwYWU0MjRiM2VjMTVhODllMTdhNGVkZjAwMTQ2NzAy
15
+ OWIwMGE2YWY3MjA4ZGIzZmZlZDZkNWI0YjJlMzc1NWEzZGY3NjY=
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Mustache
2
2
 
3
+ [![Join the chat at https://gitter.im/mustache/mustache](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mustache/mustache?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4
+
3
5
  Inspired by [ctemplate][1] and [et][2], Mustache is a
4
6
  framework-agnostic way to render logic-free views.
5
7
 
@@ -283,10 +285,8 @@ Finally, our template might look like this:
283
285
 
284
286
  ### Sinatra
285
287
 
286
- Mustache provides Sinatra integration. Please see
287
- `lib/mustache/sinatra.rb` or
288
- <https://github.com/mustache/mustache/blob/master/lib/mustache/sinatra.rb>
289
- for complete documentation.
288
+ Sinatra integration is available with the
289
+ [mustache-sinatra gem](https://github.com/mustache/mustache-sinatra).
290
290
 
291
291
  An example Sinatra application is also provided:
292
292
  <https://github.com/defunkt/mustache-sinatra-example>
@@ -388,4 +388,4 @@ You can also find us in #{ on [irc.freenode.net][irc].
388
388
  [vim]: https://github.com/mustache/vim-mustache-handlebars
389
389
  [emacs]: https://github.com/mustache/vim-mustache-handlebars
390
390
  [tmbundle]: https://github.com/defunkt/Mustache.tmbundle
391
- [diff]: https://gist.github.com/defunkt/345490
391
+ [diff]: https://gist.github.com/defunkt/345490
@@ -49,7 +49,7 @@ class Mustache
49
49
  opts.separator "Common Options:"
50
50
 
51
51
  opts.on("-v", "--version", "Print the version") do |v|
52
- puts "Mustache v#{Mustache::Version}"
52
+ puts "Mustache v#{Mustache::VERSION}"
53
53
  exit
54
54
  end
55
55
 
@@ -2,6 +2,7 @@ require 'mustache/enumerable'
2
2
  require 'mustache/template'
3
3
  require 'mustache/context'
4
4
  require 'mustache/settings'
5
+ require 'mustache/utils'
5
6
 
6
7
  # Mustache is the base class from which your Mustache subclasses
7
8
  # should inherit (though it can be used on its own).
@@ -165,14 +166,21 @@ class Mustache
165
166
  #
166
167
  # Call `render` if you need to process it.
167
168
  def self.partial(name)
168
- File.read("#{template_path}/#{name}.#{template_extension}")
169
+ self.new.partial(name)
169
170
  end
170
171
 
171
172
  # Override this in your subclass if you want to do fun things like
172
173
  # reading templates from a database. It will be rendered by the
173
174
  # context, so all you need to do is return a string.
174
175
  def partial(name)
175
- self.class.partial(name)
176
+ path = "#{template_path}/#{name}.#{template_extension}"
177
+
178
+ begin
179
+ File.read(path)
180
+ rescue
181
+ raise if raise_on_context_miss?
182
+ ""
183
+ end
176
184
  end
177
185
 
178
186
  # Override this to provide custom escaping.
@@ -246,12 +254,7 @@ class Mustache
246
254
  # template_partial => TemplatePartial
247
255
  # template/partial => Template::Partial
248
256
  def self.classify(underscored)
249
- underscored.split('/').map do |namespace|
250
- namespace.split(/[-_]/).map do |part|
251
- part[0] = part.chars.first.upcase
252
- part
253
- end.join
254
- end.join('::')
257
+ Mustache::Utils::String.new(underscored).classify
255
258
  end
256
259
 
257
260
  # TemplatePartial => template_partial
@@ -260,12 +263,7 @@ class Mustache
260
263
  def self.underscore(classified = name)
261
264
  classified = superclass.name if classified.to_s.empty?
262
265
 
263
- string = classified.dup.split("#{view_namespace}::").last
264
-
265
- string.split('::').map do |part|
266
- part[0] = part[0].downcase
267
- part.gsub(/[A-Z]/) { |s| "_" << s.downcase }
268
- end.join('/')
266
+ Mustache::Utils::String.new(classified).underscore(view_namespace)
269
267
  end
270
268
 
271
269
  # @param [Template,String] obj Turns `obj` into a template
@@ -41,7 +41,7 @@ class Mustache
41
41
  # @return [Mustache] First Mustache in the stack.
42
42
  #
43
43
  def mustache_in_stack
44
- @stack.find { |frame| frame.is_a?(Mustache) }
44
+ @mustache_in_stack ||= @stack.find { |frame| frame.is_a?(Mustache) }
45
45
  end
46
46
 
47
47
  # Allows customization of how Mustache escapes things.
@@ -62,6 +62,7 @@ class Mustache
62
62
  #
63
63
  def push(new_obj)
64
64
  @stack.unshift(new_obj)
65
+ @mustache_in_stack = nil
65
66
  self
66
67
  end
67
68
 
@@ -72,6 +73,7 @@ class Mustache
72
73
  #
73
74
  def pop
74
75
  @stack.shift
76
+ @mustache_in_stack = nil
75
77
  self
76
78
  end
77
79
 
@@ -129,7 +131,7 @@ class Mustache
129
131
  # @return [Object] The value of key in object if it is found, and default otherwise.
130
132
  #
131
133
  def find(obj, key, default = nil)
132
- return find_in_hash(obj, key, default) if obj.respond_to?(:to_hash)
134
+ return find_in_hash(obj.to_hash, key, default) if obj.respond_to?(:to_hash)
133
135
 
134
136
  key = to_tag(key)
135
137
  return default unless obj.respond_to?(key)
@@ -138,6 +140,10 @@ class Mustache
138
140
  meth.arity == 1 ? meth.to_proc : meth.call
139
141
  end
140
142
 
143
+ def current
144
+ @stack.first
145
+ end
146
+
141
147
 
142
148
  private
143
149
 
@@ -147,7 +153,8 @@ class Mustache
147
153
  key.to_s.include?('-') ? key.to_s.tr('-', '_') : key
148
154
  end
149
155
 
150
- def find_in_hash obj, key, default
156
+ # Fetches a hash key if it exists, or returns the given default.
157
+ def find_in_hash(obj, key, default)
151
158
  return obj[key] if obj.has_key?(key)
152
159
  return obj[key.to_s] if obj.has_key?(key.to_s)
153
160
 
@@ -175,7 +175,7 @@ class Mustache
175
175
  end
176
176
 
177
177
  def on_fetch(names)
178
- return "ctx[:to_s]" if names.empty?
178
+ return "ctx.current" if names.empty?
179
179
 
180
180
  names = names.map { |n| n.to_sym }
181
181
 
@@ -84,7 +84,6 @@ EOF
84
84
  # the rest only allow ALLOWED_CONTENT.
85
85
  ANY_CONTENT = [ '!', '=' ].map(&:freeze)
86
86
 
87
- attr_reader :scanner, :result
88
87
  attr_writer :otag, :ctag
89
88
 
90
89
  # Accepts an options hash which does nothing but may be used in
@@ -124,7 +123,7 @@ EOF
124
123
 
125
124
  if !@sections.empty?
126
125
  # We have parsed the whole file, but there's still opened sections.
127
- type, pos, result = @sections.pop
126
+ type, pos, _ = @sections.pop
128
127
  error "Unclosed section #{type.inspect}", pos
129
128
  end
130
129
 
@@ -135,6 +134,23 @@ EOF
135
134
  private
136
135
 
137
136
 
137
+ def content_tags type, current_ctag
138
+ if ANY_CONTENT.include?(type)
139
+ r = /\s*#{regexp(type)}?#{regexp(current_ctag)}/
140
+ scan_until_exclusive(r)
141
+ else
142
+ @scanner.scan(ALLOWED_CONTENT)
143
+ end
144
+ end
145
+
146
+ def dispatch_based_on_type type, content, fetch, padding, pre_match_position
147
+ send("scan_tag_#{type}", content, fetch, padding, pre_match_position)
148
+ end
149
+
150
+ def find_closing_tag scanner, current_ctag
151
+ error "Unclosed tag" unless scanner.scan(regexp(current_ctag))
152
+ end
153
+
138
154
  # Find {{mustaches}} and add them to the @result array.
139
155
  def scan_tags
140
156
  # Scan until we hit an opening delimiter.
@@ -161,12 +177,7 @@ EOF
161
177
 
162
178
  # ANY_CONTENT tags allow any character inside of them, while
163
179
  # other tags (such as variables) are more strict.
164
- content = if ANY_CONTENT.include?(type)
165
- r = /\s*#{regexp(type)}?#{regexp(current_ctag)}/
166
- scan_until_exclusive(r)
167
- else
168
- @scanner.scan(ALLOWED_CONTENT)
169
- end
180
+ content = content_tags(type, current_ctag)
170
181
 
171
182
  # We found {{ but we can't figure out what's going on inside.
172
183
  error "Illegal content in tag" if content.empty?
@@ -174,14 +185,7 @@ EOF
174
185
  fetch = [:mustache, :fetch, content.split('.')]
175
186
  prev = @result
176
187
 
177
- # Based on the sigil, do what needs to be done.
178
- if type
179
- # Method#call proves much faster than using send
180
- method("scan_tag_#{type}").
181
- call(content, fetch, padding, pre_match_position)
182
- else
183
- @result << [:mustache, :etag, fetch, offset]
184
- end
188
+ dispatch_based_on_type(type, content, fetch, padding, pre_match_position)
185
189
 
186
190
  # The closing } in unescaped tags is just a hack for
187
191
  # aesthetics.
@@ -192,10 +196,7 @@ EOF
192
196
  @scanner.skip(/\s+/)
193
197
  @scanner.skip(regexp(type)) if type
194
198
 
195
- # Try to find the closing tag.
196
- unless close = @scanner.scan(regexp(current_ctag))
197
- error "Unclosed tag"
198
- end
199
+ find_closing_tag(@scanner, current_ctag)
199
200
 
200
201
  # If this tag was the only non-whitespace content on this line, strip
201
202
  # the remaining whitespace. If not, but we've been hanging on to padding
@@ -282,6 +283,13 @@ EOF
282
283
  #
283
284
 
284
285
 
286
+ # This function handles the cases where the scanned tag does not have
287
+ # a type.
288
+ def scan_tag_ content, fetch, padding, pre_match_position
289
+ @result << [:mustache, :etag, fetch, offset]
290
+ end
291
+
292
+
285
293
  def scan_tag_block content, fetch, padding, pre_match_position
286
294
  block = [:multi]
287
295
  @result << [:mustache, :section, fetch, offset, block]
@@ -0,0 +1,31 @@
1
+ class Mustache
2
+ module Utils
3
+ class String
4
+ def initialize string
5
+ @string = string
6
+ end
7
+
8
+ def classify
9
+ @string.split('/').map do |namespace|
10
+ namespace.split(/[-_]/).map do |part|
11
+ part[0] = part.chars.first.upcase
12
+ part
13
+ end.join
14
+ end.join('::')
15
+ end
16
+
17
+ def underscore(view_namespace)
18
+ @string
19
+ .dup
20
+ .split("#{view_namespace}::")
21
+ .last
22
+ .split('::')
23
+ .map do |part|
24
+ part[0] = part[0].downcase
25
+ part.gsub(/[A-Z]/) { |s| "_" << s.downcase }
26
+ end
27
+ .join('/')
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,3 +1,3 @@
1
1
  class Mustache
2
- VERSION = '1.0.0'
2
+ VERSION = '1.0.1'
3
3
  end
@@ -278,14 +278,19 @@ data
278
278
  RailsEnv production
279
279
  </VirtualHost>
280
280
  data
281
- old_path, Mustache.template_path = Mustache.template_path, File.dirname(__FILE__) + "/fixtures"
282
- old_extension, Mustache.template_extension = Mustache.template_extension, "conf"
281
+ old_path = Mustache.template_path
282
+ old_extension = Mustache.template_extension
283
283
 
284
- assert_equal expected, Mustache.render(:passenger, :stage => 'production',
285
- :server => 'example.com',
286
- :deploy_to => '/var/www/example.com' )
287
-
288
- Mustache.template_path, Mustache.template_extension = old_path, old_extension
284
+ begin
285
+ Mustache.template_path = File.dirname(__FILE__) + "/fixtures"
286
+ Mustache.template_extension = "conf"
287
+
288
+ assert_equal expected, Mustache.render(:passenger, :stage => 'production',
289
+ :server => 'example.com',
290
+ :deploy_to => '/var/www/example.com')
291
+ ensure
292
+ Mustache.template_path, Mustache.template_extension = old_path, old_extension
293
+ end
289
294
  end
290
295
 
291
296
  def test_doesnt_execute_what_it_doesnt_need_to
@@ -739,4 +744,20 @@ FROM
739
744
  DUMMY1
740
745
  template
741
746
  end
747
+
748
+ def test_cast_to_hash_in_context
749
+ hashlike = Object.new
750
+ def hashlike.title
751
+ 'title'
752
+ end
753
+ def hashlike.to_hash
754
+ { title: 'title' }
755
+ end
756
+
757
+ template = '%%{{title}}%%'
758
+
759
+ assert_equal '%%title%%', Mustache.render(template, hashlike)
760
+
761
+ end
762
+
742
763
  end
@@ -59,7 +59,7 @@ Dir[spec_files].each do |file|
59
59
 
60
60
  test_suite.class_eval do
61
61
  spec['tests'].each do |test|
62
- define_method :"test - #{test['name']}" do
62
+ define_method :"test_spec - #{test['name']}" do
63
63
  setup_partials(test)
64
64
  assert_mustache_spec(test)
65
65
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mustache
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Wanstrath
@@ -11,90 +11,113 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2015-01-11 00:00:00.000000000 Z
14
+ date: 2015-02-23 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
18
18
  requirement: !ruby/object:Gem::Requirement
19
19
  requirements:
20
- - - "~>"
20
+ - - ~>
21
21
  - !ruby/object:Gem::Version
22
22
  version: '1.6'
23
23
  type: :development
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - "~>"
27
+ - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: '1.6'
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: rake
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
- - - "~>"
34
+ - - ~>
35
35
  - !ruby/object:Gem::Version
36
36
  version: '10.3'
37
37
  type: :development
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
- - - "~>"
41
+ - - ~>
42
42
  - !ruby/object:Gem::Version
43
43
  version: '10.3'
44
44
  - !ruby/object:Gem::Dependency
45
45
  name: minitest
46
46
  requirement: !ruby/object:Gem::Requirement
47
47
  requirements:
48
- - - "~>"
48
+ - - ~>
49
49
  - !ruby/object:Gem::Version
50
50
  version: '5.4'
51
51
  type: :development
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
- - - "~>"
55
+ - - ~>
56
56
  - !ruby/object:Gem::Version
57
57
  version: '5.4'
58
+ - !ruby/object:Gem::Dependency
59
+ name: benchmark-ips
60
+ requirement: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
58
72
  - !ruby/object:Gem::Dependency
59
73
  name: rdoc
60
74
  requirement: !ruby/object:Gem::Requirement
61
75
  requirements:
62
- - - "~>"
76
+ - - ~>
63
77
  - !ruby/object:Gem::Version
64
78
  version: '4.1'
65
79
  type: :development
66
80
  prerelease: false
67
81
  version_requirements: !ruby/object:Gem::Requirement
68
82
  requirements:
69
- - - "~>"
83
+ - - ~>
70
84
  - !ruby/object:Gem::Version
71
85
  version: '4.1'
72
86
  - !ruby/object:Gem::Dependency
73
87
  name: ronn
74
88
  requirement: !ruby/object:Gem::Requirement
75
89
  requirements:
76
- - - "~>"
90
+ - - ~>
77
91
  - !ruby/object:Gem::Version
78
92
  version: '0.7'
79
93
  type: :development
80
94
  prerelease: false
81
95
  version_requirements: !ruby/object:Gem::Requirement
82
96
  requirements:
83
- - - "~>"
97
+ - - ~>
84
98
  - !ruby/object:Gem::Version
85
99
  version: '0.7'
86
- description: |
87
- Inspired by ctemplate, Mustache is a framework-agnostic way to render
100
+ description: ! 'Inspired by ctemplate, Mustache is a framework-agnostic way to render
101
+
88
102
  logic-free views.
89
103
 
104
+
90
105
  As ctemplates says, "It emphasizes separating logic from presentation:
106
+
91
107
  it is impossible to embed application logic in this template
108
+
92
109
  language.
93
110
 
111
+
94
112
  Think of Mustache as a replacement for your views. Instead of views
113
+
95
114
  consisting of ERB or HAML with random helpers and arbitrary logic,
115
+
96
116
  your views are broken into two parts: a Ruby class and an HTML
117
+
97
118
  template.
119
+
120
+ '
98
121
  email: rokusu@gmail.com
99
122
  executables:
100
123
  - mustache
@@ -113,6 +136,7 @@ files:
113
136
  - lib/mustache/parser.rb
114
137
  - lib/mustache/settings.rb
115
138
  - lib/mustache/template.rb
139
+ - lib/mustache/utils.rb
116
140
  - lib/mustache/version.rb
117
141
  - man/mustache.1
118
142
  - man/mustache.1.html
@@ -181,19 +205,18 @@ require_paths:
181
205
  - lib
182
206
  required_ruby_version: !ruby/object:Gem::Requirement
183
207
  requirements:
184
- - - "~>"
208
+ - - ~>
185
209
  - !ruby/object:Gem::Version
186
210
  version: '2.0'
187
211
  required_rubygems_version: !ruby/object:Gem::Requirement
188
212
  requirements:
189
- - - ">="
213
+ - - ! '>='
190
214
  - !ruby/object:Gem::Version
191
215
  version: '0'
192
216
  requirements: []
193
217
  rubyforge_project:
194
- rubygems_version: 2.2.2
218
+ rubygems_version: 2.4.5
195
219
  signing_key:
196
220
  specification_version: 4
197
221
  summary: Mustache is a framework-agnostic way to render logic-free views.
198
222
  test_files: []
199
- has_rdoc: