mustache 1.0.0 → 1.0.1

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