prismic.io 1.0.0.rc10 → 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,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4ea682bc3f2afcc4da972445dda3adb15eff1549
4
- data.tar.gz: c47ad3c077959de4f29a90a52249163f69d784ce
3
+ metadata.gz: 8622f78a1a654d406af4edf4471810ab14e0a4a2
4
+ data.tar.gz: 3861bfec9717d19b0e047d86f4e28375b6f801d6
5
5
  SHA512:
6
- metadata.gz: 7067ccbd2b56755280c0fdc734adc14dee3c0a1ca9abe6e5462e0eeffef26dfb38f8fe32091a8de5e46b032a2c46d4037d93f48fd76fb82a9c81b942a3a1d7ea
7
- data.tar.gz: a7436d00a195ebd14ce978e11b65c52b0bd43b60ab77637d20bd88ccecaa78871faccb49539c4bfb5db0d4b9ee36e898ebf13568121551cb3c2a6c3afadcff55
6
+ metadata.gz: 962b52cb0b6fa39f30058653bbbc99e44d33be0516a30afd6a8ba3c7cae6ff1ef1643da2818e8eaa1cde8e751f532b4c881f83e75f0e929a6846a36da2e0c2f2
7
+ data.tar.gz: 004429336746943544191ae573d28fddd03dc8147292020ca4a7836fddc6d47f2748384f86004070463f8ab15b331bae88561792f8577a279121120395532da0
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  coverage/
2
2
  pkg/*.gem
3
3
  .bundle/
4
+ .idea/
5
+
data/Changelog.md ADDED
@@ -0,0 +1,7 @@
1
+ ### 1.0.0.rc10 (2014-09-10)
2
+
3
+ Features:
4
+
5
+ - Support for links in images
6
+ - Support for Timestamp fragments
7
+ - Support for Geopoint fragments
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prismic.io (1.0.0.rc10)
4
+ prismic.io (1.0.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -6,7 +6,7 @@ module Prismic
6
6
  attr_reader :expired_in
7
7
  attr_reader :data
8
8
 
9
- def initialize(data, expired_in = 0)
9
+ def initialize(data, expired_in)
10
10
  @data = data
11
11
  @expired_in = expired_in
12
12
  end
@@ -26,9 +26,9 @@ module Prismic
26
26
  include?(key) ? @cache[key].data : nil
27
27
  end
28
28
 
29
- def set(key, value = nil, expired_in = 0)
29
+ def set(key, value = nil, expired_in = nil)
30
30
  data = block_given? ? yield : value
31
- expired_in = (expired_in == 0) ? 0 : Time.now.getutc.to_i + expired_in
31
+ expired_in = expired_in && Time.now.getutc.to_i + expired_in
32
32
  entry = BasicCacheEntry.new(data, expired_in)
33
33
  @cache[key] = entry
34
34
  entry.data
@@ -38,7 +38,7 @@ module Prismic
38
38
  @cache.keys.include?(key)
39
39
  end
40
40
 
41
- def get_or_set(key, value = nil, expired_in = 0)
41
+ def get_or_set(key, value = nil, expired_in = nil)
42
42
  return get(key) if include?(key) && !expired?(key)
43
43
  set(key, block_given? ? yield : value, expired_in)
44
44
  end
@@ -51,7 +51,7 @@ module Prismic
51
51
  def expired?(key)
52
52
  if include?(key)
53
53
  expired_in = @cache[key].expired_in
54
- (expired_in != 0) && expired_in < Time.now.getutc.to_i
54
+ expired_in && expired_in < Time.now.getutc.to_i
55
55
  else
56
56
  false
57
57
  end
@@ -18,7 +18,7 @@ module Prismic
18
18
  # application's specific URL
19
19
  #
20
20
  # @return [String] the HTML representation
21
- def as_html(link_resolver=nil)
21
+ def as_html(link_resolver=nil, html_serializer=nil)
22
22
  <<-HTML
23
23
  <div data-oembed="#@url"
24
24
  data-oembed-type="#{@embed_type.downcase}"
@@ -31,7 +31,7 @@ module Prismic
31
31
  # it is not advised to override this method if you want to change the HTML output, you should
32
32
  # override the as_html method at the block level (like {Heading.as_html}, or {Preformatted.as_html},
33
33
  # for instance).
34
- def as_html(link_resolver)
34
+ def as_html(link_resolver, html_serializer=nil)
35
35
  # Defining blocks that deserve grouping, assigning them "group kind" names
36
36
  block_group = ->(block){
37
37
  case block
@@ -52,7 +52,9 @@ module Prismic
52
52
  # HTML-serializing the groups object (delegating the serialization of Block objects),
53
53
  # without forgetting to frame the BlockGroup objects right if needed
54
54
  groups.map{|group|
55
- html = group.blocks.map{|b| b.as_html(link_resolver) }.join
55
+ html = group.blocks.map { |b|
56
+ b.as_html(link_resolver, html_serializer)
57
+ }.join
56
58
  case group.kind
57
59
  when "ol"
58
60
  %(<ol>#{html}</ol>)
@@ -96,21 +98,26 @@ module Prismic
96
98
  @end = finish
97
99
  end
98
100
 
99
- class Em < Span
100
- def start_html(link_resolver=nil)
101
- "<em>"
101
+ class Label < Span
102
+ attr_accessor :label
103
+ def initialize(start, finish, label)
104
+ super(start, finish)
105
+ @label = label
102
106
  end
103
- def end_html
104
- "</em>"
107
+ def serialize(text, link_resolver = nil)
108
+ "<span class=\"#{@label}\">#{text}</span>"
105
109
  end
106
110
  end
107
111
 
108
- class Strong < Span
109
- def start_html(link_resolver=nil)
110
- "<strong>"
112
+ class Em < Span
113
+ def serialize(text, link_resolver = nil)
114
+ "<em>#{text}</em>"
111
115
  end
112
- def end_html
113
- "</strong>"
116
+ end
117
+
118
+ class Strong < Span
119
+ def serialize(text, link_resolver = nil)
120
+ "<strong>#{text}</strong>"
114
121
  end
115
122
  end
116
123
 
@@ -120,13 +127,15 @@ module Prismic
120
127
  super(start, finish)
121
128
  @link = link
122
129
  end
123
- def start_html(link_resolver = nil)
124
- link.start_html(link_resolver)
125
- end
126
- def end_html
127
- link.end_html
130
+ def serialize(text, link_resolver = nil)
131
+ if link.is_a? Prismic::Fragments::DocumentLink and link.broken
132
+ "<span>#{text}</span>"
133
+ else
134
+ %(<a href="#{link.url(link_resolver)}">#{text}</a>)
135
+ end
128
136
  end
129
137
  end
138
+
130
139
  end
131
140
 
132
141
  class Block
@@ -140,45 +149,55 @@ module Prismic
140
149
  end
141
150
 
142
151
  class Text
143
- attr_accessor :text, :spans
152
+ attr_accessor :text, :spans, :label
144
153
 
145
- def initialize(text, spans)
154
+ def initialize(text, spans, label = nil)
146
155
  @text = text
147
156
  @spans = spans.select{|span| span.start < span.end}
157
+ @label = label
148
158
  end
149
159
 
150
- def as_html(link_resolver=nil)
160
+ def class_code
161
+ (@label && %( class="#{label}")) || ''
162
+ end
163
+
164
+ def as_html(link_resolver=nil, html_serializer=nil)
165
+ html = ''
151
166
  # Getting Hashes of spanning tags to insert, sorted by starting position, and by ending position
152
167
  start_spans, end_spans = prepare_spans
153
- # All the positions in which we'll have to insert an opening or closing tag
154
- all_cuts = (start_spans.keys | end_spans.keys).sort
155
-
156
- # Initializing the browsing of the string
157
- output = []
158
- cursor = 0
159
- tags = [] # the seen tags
160
-
161
- # Taking each text cut and inserting the closing tags and the opening tags if needed
162
- all_cuts.each do |cut|
163
- output << CGI::escapeHTML(text[cursor, cut-cursor])
164
- end_tags = end_spans[cut]
165
- # reorder endings tags using creating order
166
- split = tags.group_by {|t| end_tags.include?(t) }
167
- end_tags, tags = split[true]||[], split[false]||[]
168
- output += end_tags.map{|span| span.end_html }
169
- # store created tags (in the right order)
170
- start_tags = start_spans[cut].sort_by{|s| s.end }.reverse
171
- tags += start_tags.reverse
172
- output += start_tags.map{|span| span.start_html(link_resolver) }
173
- cursor = cut # cursor is now where the cut was
168
+ # Open tags
169
+ stack = Array.new
170
+ (text.length + 1).times do |pos| # Looping to length + 1 to catch closing tags
171
+ end_spans[pos].each do |t|
172
+ # Close a tag
173
+ tag = stack.pop
174
+ inner_html = serialize(tag[:span], tag[:html], link_resolver, html_serializer)
175
+ if stack.empty?
176
+ # The tag was top-level
177
+ html += inner_html
178
+ else
179
+ # Add the content to the parent tag
180
+ stack[-1][:html] += inner_html
181
+ end
182
+ end
183
+ start_spans[pos].each do |tag|
184
+ # Open a tag
185
+ stack.push({
186
+ :span => tag,
187
+ :html => ''
188
+ })
189
+ end
190
+ if pos < text.length
191
+ if stack.empty?
192
+ # Top level text
193
+ html += CGI::escapeHTML(text[pos])
194
+ else
195
+ # Inner text of a span
196
+ stack[-1][:html] += CGI::escapeHTML(text[pos])
197
+ end
198
+ end
174
199
  end
175
-
176
- # Inserting what's left of the string, if there is something
177
- output << text[cursor..-1]
178
-
179
- # Making the array into a string
180
- output.join
181
-
200
+ html
182
201
  end
183
202
 
184
203
  # Building two span Hashes:
@@ -192,7 +211,8 @@ module Prismic
192
211
  start_spans[span.start] << span
193
212
  end_spans[span.end] << span
194
213
  }
195
- @start_spans = start_spans
214
+ # Make sure the spans are sorted bigger first to respect the hierarchy
215
+ @start_spans = start_spans.each { |_, spans| spans.sort! { |a, b| b.end - b.start <=> a.end - a.start } }
196
216
  @end_spans = end_spans
197
217
  end
198
218
  [@start_spans, @end_spans]
@@ -204,30 +224,56 @@ module Prismic
204
224
  def as_text
205
225
  @text
206
226
  end
227
+
228
+ def serialize(elt, text, link_resolver, html_serializer)
229
+ custom_html = html_serializer && html_serializer.serialize(elt, text)
230
+ if custom_html.nil?
231
+ elt.serialize(text, link_resolver)
232
+ else
233
+ custom_html
234
+ end
235
+ end
236
+
237
+ private :class_code
207
238
  end
208
239
 
209
240
  class Heading < Text
210
241
  attr_accessor :level
211
242
 
212
- def initialize(text, spans, level)
243
+ def initialize(text, spans, level, label = nil)
213
244
  super(text, spans)
214
245
  @level = level
215
246
  end
216
247
 
217
- def as_html(link_resolver=nil)
218
- %(<h#{level}>#{super}</h#{level}>)
248
+ def as_html(link_resolver=nil, html_serializer=nil)
249
+ custom_html = html_serializer && html_serializer.serialize(self, super)
250
+ if custom_html.nil?
251
+ %(<h#{level}#{class_code}>#{super}</h#{level}>)
252
+ else
253
+ custom_html
254
+ end
219
255
  end
220
256
  end
221
257
 
222
258
  class Paragraph < Text
223
- def as_html(link_resolver=nil)
224
- %(<p>#{super}</p>)
259
+ def as_html(link_resolver=nil, html_serializer=nil)
260
+ custom_html = html_serializer && html_serializer.serialize(self, super)
261
+ if custom_html.nil?
262
+ %(<p#{class_code}>#{super}</p>)
263
+ else
264
+ custom_html
265
+ end
225
266
  end
226
267
  end
227
268
 
228
269
  class Preformatted < Text
229
- def as_html(link_resolver=nil)
230
- %(<pre>#{super}</pre>)
270
+ def as_html(link_resolver=nil, html_serializer=nil)
271
+ custom_html = html_serializer && html_serializer.serialize(self, super)
272
+ if custom_html.nil?
273
+ %(<pre#{class_code}>#{super}</pre>)
274
+ else
275
+ custom_html
276
+ end
231
277
  end
232
278
  end
233
279
 
@@ -235,21 +281,27 @@ module Prismic
235
281
  attr_accessor :ordered
236
282
  alias :ordered? :ordered
237
283
 
238
- def initialize(text, spans, ordered)
284
+ def initialize(text, spans, ordered, label = nil)
239
285
  super(text, spans)
240
286
  @ordered = ordered
241
287
  end
242
288
 
243
- def as_html(link_resolver)
244
- %(<li>#{super}</li>)
289
+ def as_html(link_resolver, html_serializer=nil)
290
+ custom_html = html_serializer && html_serializer.serialize(self, super)
291
+ if custom_html.nil?
292
+ %(<li#{class_code}>#{super}</li>)
293
+ else
294
+ custom_html
295
+ end
245
296
  end
246
297
  end
247
298
 
248
299
  class Image < Block
249
- attr_accessor :view
300
+ attr_accessor :view, :label
250
301
 
251
- def initialize(view)
302
+ def initialize(view, label = nil)
252
303
  @view = view
304
+ @label = label
253
305
  end
254
306
 
255
307
  def url
@@ -276,19 +328,41 @@ module Prismic
276
328
  @view.link_to
277
329
  end
278
330
 
279
- def as_html(link_resolver)
280
- view.as_html(link_resolver)
331
+ def as_html(link_resolver, html_serializer = nil)
332
+ custom = nil
333
+ unless html_serializer.nil?
334
+ custom = html_serializer.serialize(self, '')
335
+ end
336
+ if custom.nil?
337
+ classes = ['block-img']
338
+ unless @label.nil?
339
+ classes.push(@label)
340
+ end
341
+ %(<p class="#{classes.join(' ')}">#{view.as_html(link_resolver)}</p>)
342
+ else
343
+ custom
344
+ end
281
345
  end
282
346
  end
283
347
 
284
348
  class Embed < Block
349
+ attr_accessor :label
285
350
 
286
- def initialize(embed)
287
- @embed
351
+ def initialize(embed, label)
352
+ @embed = embed
353
+ @label = label
288
354
  end
289
355
 
290
- def as_html(link_resolver)
291
- embed.as_html(link_resolver)
356
+ def as_html(link_resolver, html_serializer = nil)
357
+ custom = nil
358
+ unless html_serializer.nil?
359
+ custom = html_serializer.serialize(self, '')
360
+ end
361
+ if custom.nil?
362
+ embed.as_html(link_resolver)
363
+ else
364
+ custom
365
+ end
292
366
  end
293
367
 
294
368
  end
@@ -117,7 +117,8 @@ module Prismic
117
117
  when 'hyperlink'
118
118
  Prismic::Fragments::StructuredText::Span::Hyperlink.new(span['start'], span['end'], link_parser(span['data']))
119
119
  else
120
- puts "Unknown span_parser type: #{span['type']}"
120
+ label = span['data'] && span['data']['label']
121
+ Prismic::Fragments::StructuredText::Span::Label.new(span['start'], span['end'], label)
121
122
  end
122
123
  end
123
124
 
@@ -125,31 +126,34 @@ module Prismic
125
126
  case block['type']
126
127
  when 'paragraph'
127
128
  spans = block['spans'].map {|span| span_parser(span) }
128
- Prismic::Fragments::StructuredText::Block::Paragraph.new(block['text'], spans)
129
+ Prismic::Fragments::StructuredText::Block::Paragraph.new(block['text'], spans, block['label'])
129
130
  when 'preformatted'
130
131
  spans = block['spans'].map {|span| span_parser(span) }
131
- Prismic::Fragments::StructuredText::Block::Preformatted.new(block['text'], spans)
132
+ Prismic::Fragments::StructuredText::Block::Preformatted.new(block['text'], spans, block['label'])
132
133
  when /^heading(\d+)$/
133
134
  heading = $1
134
135
  spans = block['spans'].map {|span| span_parser(span) }
135
136
  Prismic::Fragments::StructuredText::Block::Heading.new(
136
137
  block['text'],
137
138
  spans,
138
- heading.to_i
139
+ heading.to_i,
140
+ block['label']
139
141
  )
140
142
  when 'o-list-item'
141
143
  spans = block['spans'].map {|span| span_parser(span) }
142
144
  Prismic::Fragments::StructuredText::Block::ListItem.new(
143
145
  block['text'],
144
146
  spans,
145
- true # ordered
147
+ true, # ordered
148
+ block['label']
146
149
  )
147
150
  when 'list-item'
148
151
  spans = block['spans'].map {|span| span_parser(span) }
149
152
  Prismic::Fragments::StructuredText::Block::ListItem.new(
150
153
  block['text'],
151
154
  spans,
152
- false # unordered
155
+ false, # unordered
156
+ block['label']
153
157
  )
154
158
  when 'image'
155
159
  view = Prismic::Fragments::Image::View.new(
@@ -160,7 +164,7 @@ module Prismic
160
164
  block['copyright'],
161
165
  block['linkTo'] ? link_parser(block['linkTo']) : nil
162
166
  )
163
- Prismic::Fragments::StructuredText::Block::Image.new(view)
167
+ Prismic::Fragments::StructuredText::Block::Image.new(view, block['label'])
164
168
  when 'embed'
165
169
  boembed = block['oembed']
166
170
  Prismic::Fragments::Embed.new(
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
  module Prismic
3
3
 
4
- VERSION = "1.0.0.rc10"
4
+ VERSION = '1.0.1'
5
5
 
6
6
  end
data/lib/prismic.rb CHANGED
@@ -520,6 +520,16 @@ module Prismic
520
520
  end
521
521
  end
522
522
 
523
+ class HtmlSerializer
524
+ def initialize(&blk)
525
+ @blk = blk
526
+ end
527
+
528
+ def serialize(element, content)
529
+ @blk.call(element, content)
530
+ end
531
+ end
532
+
523
533
  # Default HTTP client implementation, using the standard Net::HTTP library.
524
534
  module DefaultHTTPClient
525
535
  class << self
@@ -586,6 +596,10 @@ module Prismic
586
596
  LinkResolver.new(ref, &blk)
587
597
  end
588
598
 
599
+ def self.html_serializer(&blk)
600
+ HtmlSerializer.new(&blk)
601
+ end
602
+
589
603
  end
590
604
 
591
605
  require 'prismic/api'
data/prismic.gemspec CHANGED
@@ -6,7 +6,7 @@ require 'prismic/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "prismic.io"
8
8
  spec.version = Prismic::VERSION
9
- spec.authors = ["Étienne Vallette d'Osia", "Samy Dindane", "Rudy Rigot"]
9
+ spec.authors = ["Étienne Vallette d'Osia", "Erwan Loisant", "Samy Dindane", "Rudy Rigot"]
10
10
  spec.email = ["evo@zenexity.com"]
11
11
  spec.description = %q{The standard Prismic.io's API library.}
12
12
  spec.summary = %q{Prismic.io development kit}
data/spec/cache_spec.rb CHANGED
@@ -95,17 +95,17 @@ describe "Basic Cache's" do
95
95
 
96
96
  it 'set with expiration value & get value' do
97
97
  cache = Prismic::BasicCache.new
98
- cache.set('key', 'value', 2)
99
- sleep(3)
98
+ cache.set('key', 'value', 1)
99
+ sleep(2)
100
100
  cache.get('key').should == nil
101
101
  end
102
102
 
103
103
  it 'set with expiration and a block' do
104
104
  cache = Prismic::BasicCache.new
105
- cache.get_or_set('key', nil, 2){ 'value' }
106
- cache.get_or_set('key', nil, 2){ 'othervalue' }.should == 'value'
107
- sleep(3)
108
- cache.get_or_set('key', nil, 2){ 'othervalue' }.should == 'othervalue'
105
+ cache.get_or_set('key', nil, 1){ 'value' }
106
+ cache.get_or_set('key', nil, 1){ 'othervalue' }.should == 'value'
107
+ sleep(2)
108
+ cache.get_or_set('key', nil, 1){ 'othervalue' }.should == 'othervalue'
109
109
  end
110
110
 
111
111
  it 'set & test value' do
@@ -93,7 +93,7 @@ describe 'ImageLink' do
93
93
 
94
94
  describe 'url' do
95
95
  before do
96
- @link_resolver = Prismic.link_resolver("master"){|doc_link| "http://localhost/#{doc_link.id}" }
96
+ @link_resolver = Prismic.link_resolver('master'){|doc_link| "http://localhost/#{doc_link.id}" }
97
97
  end
98
98
  it 'works in a unified way' do
99
99
  @image_link.url(@link_resolver).should == 'my_url'
@@ -109,7 +109,10 @@ describe 'FileLink' do
109
109
  @structured_text = Prismic::JsonParser.structured_text_parser(@json_structured_text)
110
110
  end
111
111
  it 'serializes well into HTML' do
112
- @structured_text.as_html(nil).should == "<p><a href=\"https://prismic-io.s3.amazonaws.com/annual.report.pdf\">2012 Annual Report</a></p>\n\n<p><a href=\"https://prismic-io.s3.amazonaws.com/annual.budget.pdf\">2012 Annual Budget</a></p>\n\n<p><a href=\"https://prismic-io.s3.amazonaws.com/vision.strategic.plan_.sm_.pdf\">2015 Vision &amp; Strategic Plan</a></p>"
112
+ @structured_text.as_html(nil).should ==
113
+ "<p><a href=\"https://prismic-io.s3.amazonaws.com/annual.report.pdf\">2012 Annual Report</a></p>\n\n"\
114
+ "<p><a href=\"https://prismic-io.s3.amazonaws.com/annual.budget.pdf\">2012 Annual Budget</a></p>\n\n"\
115
+ "<p><a href=\"https://prismic-io.s3.amazonaws.com/vision.strategic.plan_.sm_.pdf\">2015 Vision &amp; Strategic Plan</a></p>"
113
116
  end
114
117
  end
115
118
  end
@@ -122,7 +125,10 @@ describe 'Span' do
122
125
  @structured_text = Prismic::JsonParser.structured_text_parser(@json_structured_text)
123
126
  end
124
127
  it 'serializes well into HTML' do
125
- @structured_text.as_html(nil).should == "<h3><strong>Powering Through 2013 </strong></h3>\n\n<h3><strong>Online Resources:</strong></h3>\n\n<ul><li>Hear more from our executive team as they reflect on 2013 and share their vision for 2014 on our blog <a href=\"http://prismic.io\">here</a></li></ul>"
128
+ @structured_text.as_html(nil).should ==
129
+ "<h3><strong>Powering Through 2013 </strong></h3>\n\n"\
130
+ "<h3><strong>Online Resources:</strong></h3>\n\n"\
131
+ "<ul><li>Hear more from our executive team as they reflect on 2013 and share their vision for 2014 on our blog <a href=\"http://prismic.io\">here</a></li></ul>"
126
132
  end
127
133
  end
128
134
  describe 'in structured texts when multiple spans' do
@@ -132,7 +138,9 @@ describe 'Span' do
132
138
  @structured_text = Prismic::JsonParser.structured_text_parser(@json_structured_text)
133
139
  end
134
140
  it 'serializes well into HTML' do
135
- @structured_text.as_html(nil).should == "<p>Experience <a href=\"http://prismic.io\">the</a> ultimate vanilla experience. Our vanilla Macarons are made with our very own (in-house) <em>pure extract of Madagascar vanilla</em>, and subtly dusted with <strong>our own vanilla sugar</strong> (which we make from real vanilla beans).</p>"
141
+ @structured_text.as_html(nil).should ==
142
+ '<p class="vanilla">Experience <a href="http://prismic.io">the</a> ultimate vanilla experience. '\
143
+ 'Our vanilla Macarons are made with our very own (in-house) <em>pure extract of Madagascar vanilla</em>, and subtly dusted with <strong>our own vanilla sugar</strong> (which we make from real vanilla beans).</p>'
136
144
  end
137
145
  end
138
146
  end
@@ -507,17 +515,17 @@ end
507
515
 
508
516
  describe 'StructuredText::Heading' do
509
517
  before do
510
- @text = "This is a simple test."
518
+ @text = 'This is a simple test.'
511
519
  @spans = [em(5, 7), strong(8, 9)]
512
520
  end
513
521
  let :block do Prismic::Fragments::StructuredText::Block::Heading.new(@text, @spans, @heading) end
514
522
  it 'generates valid h1 html' do
515
523
  @heading = 1
516
- block.as_html(nil).should == "<h1>This <em>is</em> <strong>a</strong> simple test.</h1>"
524
+ block.as_html(nil).should == '<h1>This <em>is</em> <strong>a</strong> simple test.</h1>'
517
525
  end
518
526
  it 'generates valid h2 html' do
519
527
  @heading = 2
520
- block.as_html(nil).should == "<h2>This <em>is</em> <strong>a</strong> simple test.</h2>"
528
+ block.as_html(nil).should == '<h2>This <em>is</em> <strong>a</strong> simple test.</h2>'
521
529
  end
522
530
  end
523
531
 
@@ -546,7 +554,7 @@ describe 'StructuredText::Paragraph' do
546
554
  it "espaces HTML content (2 spans on the same text)" do
547
555
  @text = 'abcdefghijklmnopqrstuvwxyz'
548
556
  @spans = [em(2, 4), strong(2, 4)]
549
- block.as_html(nil).should =~ %r{^<[^>]+>ab<strong><em>cd</em></strong>efghijklmnopqrstuvwxyz<[^>]+>$}
557
+ block.as_html(nil).should =~ %r{^<[^>]+>ab<em><strong>cd</strong></em>efghijklmnopqrstuvwxyz<[^>]+>$}
550
558
  end
551
559
  it "espaces HTML content (2 spans on the same text - one bigger 1)" do
552
560
  @text = 'abcdefghijklmnopqrstuvwxyz'
@@ -626,14 +634,14 @@ describe 'StructuredText::Hyperlink' do
626
634
 
627
635
  describe 'as_html' do
628
636
  it "can generate valid link" do
629
- @hyperlink.start_html(@link_resolver).should == '<a href="http://localhost/UdUjvt_mqVNObPeO">'
637
+ @hyperlink.serialize('', @link_resolver).should == '<a href="http://localhost/UdUjvt_mqVNObPeO"></a>'
630
638
  end
631
639
  it "raises an error when no link_resolver provided" do
632
- expect { @hyperlink.start_html(nil) }.to raise_error
640
+ expect { @hyperlink.serialize('', nil) }.to raise_error
633
641
  end
634
642
  it "can generate valid html for broken link" do
635
643
  @link.broken = true
636
- @hyperlink.start_html(@link_resolver).should == "<span>"
644
+ @hyperlink.serialize('', @link_resolver).should == '<span></span>'
637
645
  end
638
646
  end
639
647
  end
@@ -221,13 +221,13 @@ describe 'image_parser in StructuredText' do
221
221
 
222
222
  <p>The following image is linked.</p>
223
223
 
224
- <a href="http://google.com/"><img src="http://fpoimg.com/129x260" alt="" width="260" height="129" /></a>
224
+ <p class="block-img"><a href="http://google.com/"><img src="http://fpoimg.com/129x260" alt="" width="260" height="129" /></a></p>
225
225
 
226
226
  <p><strong>More important stuff</strong></p>
227
227
 
228
228
  <p>One more image, this one is not linked:</p>
229
229
 
230
- <img src="http://fpoimg.com/199x300" alt="" width="300" height="199" />
230
+ <p class="block-img"><img src="http://fpoimg.com/199x300" alt="" width="300" height="199" /></p>
231
231
  expected
232
232
  expected.chomp!
233
233
  link_resolver = Prismic.link_resolver("master"){|doc_link| "http://localhost/#{doc_link.id}" }
@@ -442,8 +442,39 @@ describe 'unknown_parser' do
442
442
  @json = JSON.load(@raw_json)
443
443
  end
444
444
 
445
- it "raises the proper error" do
445
+ it 'raises the proper error' do
446
446
  Prismic::JsonParser.should_receive(:warn).with("Type blabla is unknown, fragment was skipped; perhaps you should update your prismic.io gem?")
447
447
  Prismic::JsonParser.document_parser(@json).fragments.size.should == 2
448
448
  end
449
449
  end
450
+
451
+ describe 'structured_text_label_parser' do
452
+ before do
453
+ raw_json = File.read("#{File.dirname(__FILE__)}/responses_mocks/structured_text_with_labels.json")
454
+ json = JSON.load(raw_json)
455
+ @structured_text = Prismic::JsonParser.structured_text_parser(json)
456
+ end
457
+
458
+ it 'outputs correctly as HTML' do
459
+ link_resolver = Prismic.link_resolver("master"){|doc_link| "http://localhost/#{doc_link.id}" }
460
+ @structured_text.as_html(link_resolver).should ==
461
+ "<h1>Tips to dress a pastry</h1>\n\n" +
462
+ "<p class=\"block-img\"><img src=\"https://prismic-io.s3.amazonaws.com/lesbonneschoses-vcerzcwaaohojzo/381f3a78dfe952b229fb49ceaa9926f7009ae20a.jpg\" alt=\"\" width=\"640\" height=\"666\" /></p>\n\n" +
463
+ "<p>Our Pastry Dressers (yes, it is <a href=\"http://localhost/UlfoxUnM0wkXYXbh\">a full-time job</a> in <em>Les Bonnes Choses</em>!) have it somewhat different from our other pastry artists: while the others keep their main focus on the taste, smell, and potentially touch of your pastries, the Pastry Dressers are mainly focused on their looks.</p>\n\n" +
464
+ "<p>It sometimes makes them feem like they&#39;re doing a job that is reasonably different from plain old pastry, and to make the most of your pastry dressings, perhaps so should you!</p>\n\n" +
465
+ "<h2>Step by step</h2>\n\n" +
466
+ "<p>From bottom to top, the steps towards a great dressing are pretty clear, and change rarely.</p>\n\n" +
467
+ "<h3>Pastry Dresser, or speleologist?</h3>\n\n" +
468
+ "<p>One of the first handy phases of dressing your pastry will be about carving to get to a desired shape and size to build upon. This is very precise work, as you will need to <span class=\"author\">clean</span> the object without breaking it, to remove pieces of it while keeping intact the meaningful bits. Now you&#39;re ready to iterate upon it!</p>\n\n" +
469
+ "<h3>Pastry Dresser, or clay sculptor?</h3>\n\n<p>" +
470
+ "Then, you will need to shape your piece of art <span class=\"author\"><strong>into</strong></span> the design you have in mind, by adding the right materials to just the right places. Ganache is your friend in such moments, such as any shape-free material. You&#39;ll have to master them, so they obey to the shapes you have in mind.</p>\n\n" +
471
+ "<h3>Pastry Dresser, or hairdresser?</h3>\n\n" +
472
+ "<p>The top of the pastry is a priority zone for finalization. This is where your &quot;last touch&quot; goes, and it&#39;s tremendously important, as it gives the pastry most of its character. You will have to play with the details, to keep the top of your piece on the... top of your priorities!</p>\n\n<h2>Before starting</h2>\n\n<p>" +
473
+ "Finishing by the beginning: what did we have to consider, before running towards the aforementioned steps?</p>\n\n" +
474
+ "<p class=\"block-img\"><img src=\"https://prismic-io.s3.amazonaws.com/lesbonneschoses-vcerzcwaaohojzo/502ebb427b5eb45693800816fc778316c04935f5.jpg\" alt=\"\" width=\"640\" height=\"427\" /></p>\n\n" +
475
+ "<h3>Pastry Dresser, or illustrator?</h3>\n\n" +
476
+ "<p>We didn&#39;t mention color, but it&#39;s a very important component of the piece. Just like an illustrator will pick colors that add to the shape in a matching way to keep a perfect meaning, the colors must be perfect to be consistent with the taste of the piece (do not use green-colored sugar for a strawberry-flavored pastry, if you don&#39;t want to gross people out!)</p>\n\n" +
477
+ "<h3>Pastry Dresser, or designer?</h3>\n\n<p>And even before the illustration and colors, you really need to take the time to think about your destination, to make sure it&#39;s nothing short of perfect. This may imply taking the time to sit down for a few minutes with a paper and a pen. The first skill of an imaginative Pastry Dresser is a drawing skill, just like a fashion stylist.</p>"
478
+ end
479
+
480
+ end
@@ -121,17 +121,68 @@ describe 'LesBonnesChoses' do
121
121
  describe 'Fragments' do
122
122
  before do
123
123
  @link_resolver = Prismic.link_resolver("master"){|doc_link| "http://localhost/#{doc_link.id}" }
124
+ @html_serializer = Prismic.html_serializer do |element, html|
125
+ if element.is_a?(Prismic::Fragments::StructuredText::Block::Image)
126
+ %(<img src="#{element.url}" alt="#{element.alt}" width="#{element.width}" height="#{element.height}" />)
127
+ else
128
+ nil
129
+ end
130
+ end
124
131
  end
125
132
  describe 'API::Fragments::StructuredText' do
126
133
  it "returns a correct as_html on a StructuredText with list, span, embed and image" do
127
134
  @api.form("everything")
128
135
  .query(%([[:d = at(document.id, "UlfoxUnM0wkXYXbX")]]))
129
- .submit(@master_ref)[0]['blog-post.body'].as_html(@link_resolver).gsub("&#39;", "'").should == "<h1>Get the right approach to ganache</h1>\n\n<p>A lot of people touch base with us to know about one of our key ingredients, and the essential role it plays in our creations: ganache.</p>\n\n<p>Indeed, ganache is the macaron's softener, or else, macarons would be but tough biscuits; it is the cupcake's wrapper, or else, cupcakes would be but plain old cake. We even sometimes use ganache within our cupcakes, to soften the cake itself, or as a support to our pies' content.</p>\n\n<h2>How to approach ganache</h2>\n\n<img src=\"https://prismic-io.s3.amazonaws.com/lesbonneschoses/ee7b984b98db4516aba2eabd54ab498293913c6c.jpg\" alt=\"\" width=\"640\" height=\"425\" />\n\n<p>Apart from the taste balance, which is always a challenge when it comes to pastry, the tough part about ganache is about thickness. It is even harder to predict through all the phases the ganache gets to meet (how long will it get melted? how long will it remain in the fridge?). Things get a hell of a lot easier to get once you consider that there are two main ways to get the perfect ganache:</p>\n\n<ul><li><strong>working from the top down</strong>: start with a thick, almost hard material, and soften it by manipulating it, or by mixing it with a more liquid ingredient (like milk)</li><li><strong>working from the bottom up</strong>: start from a liquid-ish state, and harden it by miwing it with thicker ingredients, or by leaving it in the fridge longer.</li></ul>\n\n<p>We do hope this advice will empower you in your ganache-making skills. Let us know how you did with it!</p>\n\n<h2>Ganache at <em>Les Bonnes Choses</em></h2>\n\n<p>We have a saying at Les Bonnes Choses: \"Once you can make ganache, you can make anything.\"</p>\n\n<p>As you may know, we like to give our workshop artists the ability to master their art to the top; that is why our Preparation Experts always start off as being Ganache Specialists for Les Bonnes Choses. That way, they're given an opportunity to focus on one exercise before moving on. Once they master their ganache, and are able to provide the most optimal delight to our customers, we consider they'll thrive as they work on other kinds of preparations.</p>\n\n<h2>About the chocolate in our ganache</h2>\n\n<p>Now, we've also had a lot of questions about how our chocolate gets made. It's true, as you might know, that we make it ourselves, from Columbian cocoa and French cow milk, with a process that much resembles the one in the following Discovery Channel documentary.</p>\n\n <div data-oembed=\"http://www.youtube.com/\"\n data-oembed-type=\"video\"\n data-oembed-provider=\"youtube\"><iframe width=\"459\" height=\"344\" src=\"http://www.youtube.com/embed/Ye78F3-CuXY?feature=oembed\" frameborder=\"0\" allowfullscreen></iframe></div>\n"
136
+ .submit(@master_ref)[0]['blog-post.body'].as_html(@link_resolver).gsub("&#39;", "'").should ==
137
+ "<h1>Get the right approach to ganache</h1>\n\n"\
138
+ "<p>A lot of people touch base with us to know about one of our key ingredients, and the essential role it plays in our creations: ganache.</p>\n\n"\
139
+ "<p>Indeed, ganache is the macaron's softener, or else, macarons would be but tough biscuits; it is the cupcake's wrapper, or else, cupcakes would be but plain old cake. We even sometimes use ganache within our cupcakes, to soften the cake itself, or as a support to our pies' content.</p>\n\n"\
140
+ "<h2>How to approach ganache</h2>\n\n"\
141
+ "<p class=\"block-img\"><img src=\"https://prismic-io.s3.amazonaws.com/lesbonneschoses/ee7b984b98db4516aba2eabd54ab498293913c6c.jpg\" alt=\"\" width=\"640\" height=\"425\" /></p>\n\n"\
142
+ "<p>Apart from the taste balance, which is always a challenge when it comes to pastry, the tough part about ganache is about thickness. It is even harder to predict through all the phases the ganache gets to meet (how long will it get melted? how long will it remain in the fridge?). "\
143
+ "Things get a hell of a lot easier to get once you consider that there are two main ways to get the perfect ganache:</p>\n\n"\
144
+ "<ul><li><strong>working from the top down</strong>: start with a thick, almost hard material, and soften it by manipulating it, or by mixing it with a more liquid ingredient (like milk)</li>"\
145
+ "<li><strong>working from the bottom up</strong>: start from a liquid-ish state, and harden it by miwing it with thicker ingredients, or by leaving it in the fridge longer.</li></ul>\n\n"\
146
+ "<p>We do hope this advice will empower you in your ganache-making skills. Let us know how you did with it!</p>\n\n"\
147
+ "<h2>Ganache at <em>Les Bonnes Choses</em></h2>\n\n"\
148
+ "<p>We have a saying at Les Bonnes Choses: &quot;Once you can make ganache, you can make anything.&quot;</p>\n\n"\
149
+ "<p>As you may know, we like to give our workshop artists the ability to master their art to the top; that is why our Preparation Experts always start off as being Ganache Specialists for Les Bonnes Choses. That way, they're given an opportunity to focus on one exercise before moving on. "\
150
+ "Once they master their ganache, and are able to provide the most optimal delight to our customers, we consider they'll thrive as they work on other kinds of preparations.</p>\n\n"\
151
+ "<h2>About the chocolate in our ganache</h2>\n\n"\
152
+ "<p>Now, we've also had a lot of questions about how our chocolate gets made. It's true, as you might know, that we make it ourselves, from Columbian cocoa and French cow milk, with a process that much resembles the one in the following Discovery Channel documentary.</p>\n\n "\
153
+ "<div data-oembed=\"http://www.youtube.com/\"\n data-oembed-type=\"video\"\n data-oembed-provider=\"youtube\"><iframe width=\"459\" height=\"344\" src=\"http://www.youtube.com/embed/Ye78F3-CuXY?feature=oembed\" frameborder=\"0\" allowfullscreen></iframe></div>\n"
154
+ end
155
+ it "returns a correct as_html on a StructuredText with custom HTML serializer" do
156
+ @api.form("everything")
157
+ .query(%([[:d = at(document.id, "#{@api.bookmark('about')}")]]))
158
+ .submit(@master_ref)[0]['article.content'].as_html(@link_resolver, @html_serializer).gsub("&#39;", "'").should ==
159
+ "<h2>A tale of pastry and passion</h2>\n\n"\
160
+ "<p>As a child, Jean-Michel Pastranova learned the art of fine cuisine from his grand-father, Jacques Pastranova, who was the creator of the &quot;taste-design&quot; art current, and still today an unmissable reference of forward-thinking in cuisine. At first an assistant in his grand-father's kitchen, Jean-Michel soon found himself fascinated by sweet flavors and the tougher art of pastry, drawing his own path in the ever-changing cuisine world.</p>\n\n"\
161
+ "<p>In 1992, the first Les Bonnes Choses store opened on rue Saint-Lazare, in Paris (<a href=\"http://localhost/UlfoxUnM0wkXYXbb\">we're still there!</a>), much to everyone's surprise; indeed, back then, it was very surprising for a highly promising young man with a preordained career as a restaurant chef, to open a pastry shop instead. But soon enough, contemporary chefs understood that Jean-Michel had the drive to redefine a new nobility to pastry, the same way many other kinds of cuisine were being qualified as &quot;fine&quot;.</p>\n\n"\
162
+ "<p>In 1996, meeting an overwhelming demand, Jean-Michel Pastranova opened <a href=\"http://localhost/UlfoxUnM0wkXYXbP\">a second shop on Paris's Champs-Élysées</a>, and <a href=\"http://localhost/UlfoxUnM0wkXYXbr\">a third one in London</a>, the same week! Eventually, Les Bonnes Choses gained an international reputation as &quot;a perfection so familiar and new at the same time, that it will feel like a taste travel&quot; (New York Gazette), &quot;the finest balance between surprise and comfort, enveloped in sweetness&quot; (The Tokyo Tribune), &quot;a renewal of the pastry genre (...), the kind that changed the way pastry is approached globally&quot; (The San Francisco Gourmet News). Therefore, it was only a matter of time before Les Bonnes Choses opened shops in <a href=\"http://localhost/UlfoxUnM0wkXYXbc\">New York</a> (2000) and <a href=\"http://localhost/UlfoxUnM0wkXYXbU\">Tokyo</a> (2004).</p>\n\n"\
163
+ "<p>In 2013, Jean-Michel Pastranova stepped down as the CEO and Director of Workshops, remaining a senior advisor to the board and to the workshop artists; he passed the light on to Selena, his daugther, who initially learned the art of pastry from him. Passion for great food runs in the Pastranova family...</p>\n\n<img src=\"https://prismic-io.s3.amazonaws.com/lesbonneschoses/df6c1d87258a5bfadf3479b163fd85c829a5c0b8.jpg\" alt=\"\" width=\"800\" height=\"533\" />\n\n"\
164
+ "<h2>Our main value: our customers' delight</h2>\n\n"\
165
+ "<p>Our every action is driven by the firm belief that there is art in pastry, and that this art is one of the dearest pleasures one can experience.</p>\n\n"\
166
+ "<p>At Les Bonnes Choses, people preparing your macarons are not simply &quot;pastry chefs&quot;: they are &quot;<a href=\"http://localhost/UlfoxUnM0wkXYXba\">ganache specialists</a>&quot;, &quot;<a href=\"http://localhost/UlfoxUnM0wkXYXbQ\">fruit experts</a>&quot;, or &quot;<a href=\"http://localhost/UlfoxUnM0wkXYXbn\">oven instrumentalists</a>&quot;. They are the best people out there to perform the tasks they perform to create your pastry, giving it the greatest value. And they just love to make their specialized pastry skill better and better until perfection.</p>\n\n"\
167
+ "<p>Of course, there is a workshop in each <em>Les Bonnes Choses</em> store, and every pastry you buy was made today, by the best pastry specialists in your country.</p>\n\n"\
168
+ "<p>However, the very difficult art of creating new concepts, juggling with tastes and creating brand new, powerful experiences, is performed every few months, during our &quot;<a href=\"http://localhost/UlfoxUnM0wkXYXbl\">Pastry Art Brainstorms</a>&quot;. During the event, the best pastry artists in the world (some working for <em>Les Bonnes Choses</em>, some not) gather in Paris, and showcase the experiments they've been working on; then, the other present artists comment on the piece, and iterate on it together, in order to make it the best possible masterchief!</p>\n\n"\
169
+ "<p>The session is presided by Jean-Michel Pastranova, who then selects the most delightful experiences, to add it to <em>Les Bonnes Choses</em>'s catalogue.</p>"
130
170
  end
131
171
  it "returns a correct as_html on a StructuredText with links" do
132
172
  @api.form("everything")
133
173
  .query(%([[:d = at(document.id, "#{@api.bookmark('about')}")]]))
134
- .submit(@master_ref)[0]['article.content'].as_html(@link_resolver).gsub("&#39;", "'").should == "<h2>A tale of pastry and passion</h2>\n\n<p>As a child, Jean-Michel Pastranova learned the art of fine cuisine from his grand-father, Jacques Pastranova, who was the creator of the \"taste-design\" art current, and still today an unmissable reference of forward-thinking in cuisine. At first an assistant in his grand-father's kitchen, Jean-Michel soon found himself fascinated by sweet flavors and the tougher art of pastry, drawing his own path in the ever-changing cuisine world.</p>\n\n<p>In 1992, the first Les Bonnes Choses store opened on rue Saint-Lazare, in Paris (<a href=\"http://localhost/UlfoxUnM0wkXYXbb\">we're still there!</a>), much to everyone's surprise; indeed, back then, it was very surprising for a highly promising young man with a preordained career as a restaurant chef, to open a pastry shop instead. But soon enough, contemporary chefs understood that Jean-Michel had the drive to redefine a new nobility to pastry, the same way many other kinds of cuisine were being qualified as \"fine\".</p>\n\n<p>In 1996, meeting an overwhelming demand, Jean-Michel Pastranova opened <a href=\"http://localhost/UlfoxUnM0wkXYXbP\">a second shop on Paris's Champs-Élysées</a>, and <a href=\"http://localhost/UlfoxUnM0wkXYXbr\">a third one in London</a>, the same week! Eventually, Les Bonnes Choses gained an international reputation as &quot;a perfection so familiar and new at the same time, that it will feel like a taste travel&quot; (New York Gazette), &quot;the finest balance between surprise and comfort, enveloped in sweetness&quot; (The Tokyo Tribune), &quot;a renewal of the pastry genre (...), the kind that changed the way pastry is approached globally&quot; (The San Francisco Gourmet News). Therefore, it was only a matter of time before Les Bonnes Choses opened shops in <a href=\"http://localhost/UlfoxUnM0wkXYXbc\">New York</a> (2000) and <a href=\"http://localhost/UlfoxUnM0wkXYXbU\">Tokyo</a> (2004).</p>\n\n<p>In 2013, Jean-Michel Pastranova stepped down as the CEO and Director of Workshops, remaining a senior advisor to the board and to the workshop artists; he passed the light on to Selena, his daugther, who initially learned the art of pastry from him. Passion for great food runs in the Pastranova family...</p>\n\n<img src=\"https://prismic-io.s3.amazonaws.com/lesbonneschoses/df6c1d87258a5bfadf3479b163fd85c829a5c0b8.jpg\" alt=\"\" width=\"800\" height=\"533\" />\n\n<h2>Our main value: our customers' delight</h2>\n\n<p>Our every action is driven by the firm belief that there is art in pastry, and that this art is one of the dearest pleasures one can experience.</p>\n\n<p>At Les Bonnes Choses, people preparing your macarons are not simply &quot;pastry chefs&quot;: they are &quot;<a href=\"http://localhost/UlfoxUnM0wkXYXba\">ganache specialists</a>&quot;, &quot;<a href=\"http://localhost/UlfoxUnM0wkXYXbQ\">fruit experts</a>&quot;, or &quot;<a href=\"http://localhost/UlfoxUnM0wkXYXbn\">oven instrumentalists</a>\". They are the best people out there to perform the tasks they perform to create your pastry, giving it the greatest value. And they just love to make their specialized pastry skill better and better until perfection.</p>\n\n<p>Of course, there is a workshop in each <em>Les Bonnes Choses</em> store, and every pastry you buy was made today, by the best pastry specialists in your country.</p>\n\n<p>However, the very difficult art of creating new concepts, juggling with tastes and creating brand new, powerful experiences, is performed every few months, during our &quot;<a href=\"http://localhost/UlfoxUnM0wkXYXbl\">Pastry Art Brainstorms</a>&quot;. During the event, the best pastry artists in the world (some working for <em>Les Bonnes Choses</em>, some not) gather in Paris, and showcase the experiments they've been working on; then, the other present artists comment on the piece, and iterate on it together, in order to make it the best possible masterchief!</p>\n\n<p>The session is presided by Jean-Michel Pastranova, who then selects the most delightful experiences, to add it to <em>Les Bonnes Choses</em>'s catalogue.</p>"
174
+ .submit(@master_ref)[0]['article.content'].as_html(@link_resolver).gsub("&#39;", "'").should ==
175
+ "<h2>A tale of pastry and passion</h2>\n\n"\
176
+ "<p>As a child, Jean-Michel Pastranova learned the art of fine cuisine from his grand-father, Jacques Pastranova, who was the creator of the &quot;taste-design&quot; art current, and still today an unmissable reference of forward-thinking in cuisine. At first an assistant in his grand-father's kitchen, Jean-Michel soon found himself fascinated by sweet flavors and the tougher art of pastry, drawing his own path in the ever-changing cuisine world.</p>\n\n"\
177
+ "<p>In 1992, the first Les Bonnes Choses store opened on rue Saint-Lazare, in Paris (<a href=\"http://localhost/UlfoxUnM0wkXYXbb\">we're still there!</a>), much to everyone's surprise; indeed, back then, it was very surprising for a highly promising young man with a preordained career as a restaurant chef, to open a pastry shop instead. But soon enough, contemporary chefs understood that Jean-Michel had the drive to redefine a new nobility to pastry, the same way many other kinds of cuisine were being qualified as &quot;fine&quot;.</p>\n\n"\
178
+ "<p>In 1996, meeting an overwhelming demand, Jean-Michel Pastranova opened <a href=\"http://localhost/UlfoxUnM0wkXYXbP\">a second shop on Paris's Champs-Élysées</a>, and <a href=\"http://localhost/UlfoxUnM0wkXYXbr\">a third one in London</a>, the same week! Eventually, Les Bonnes Choses gained an international reputation as &quot;a perfection so familiar and new at the same time, that it will feel like a taste travel&quot; (New York Gazette), &quot;the finest balance between surprise and comfort, enveloped in sweetness&quot; (The Tokyo Tribune), &quot;a renewal of the pastry genre (...), the kind that changed the way pastry is approached globally&quot; (The San Francisco Gourmet News). Therefore, it was only a matter of time before Les Bonnes Choses opened shops in <a href=\"http://localhost/UlfoxUnM0wkXYXbc\">New York</a> (2000) and <a href=\"http://localhost/UlfoxUnM0wkXYXbU\">Tokyo</a> (2004).</p>\n\n"\
179
+ "<p>In 2013, Jean-Michel Pastranova stepped down as the CEO and Director of Workshops, remaining a senior advisor to the board and to the workshop artists; he passed the light on to Selena, his daugther, who initially learned the art of pastry from him. Passion for great food runs in the Pastranova family...</p>\n\n<p class=\"block-img\"><img src=\"https://prismic-io.s3.amazonaws.com/lesbonneschoses/df6c1d87258a5bfadf3479b163fd85c829a5c0b8.jpg\" alt=\"\" width=\"800\" height=\"533\" /></p>\n\n"\
180
+ "<h2>Our main value: our customers' delight</h2>\n\n"\
181
+ "<p>Our every action is driven by the firm belief that there is art in pastry, and that this art is one of the dearest pleasures one can experience.</p>\n\n"\
182
+ "<p>At Les Bonnes Choses, people preparing your macarons are not simply &quot;pastry chefs&quot;: they are &quot;<a href=\"http://localhost/UlfoxUnM0wkXYXba\">ganache specialists</a>&quot;, &quot;<a href=\"http://localhost/UlfoxUnM0wkXYXbQ\">fruit experts</a>&quot;, or &quot;<a href=\"http://localhost/UlfoxUnM0wkXYXbn\">oven instrumentalists</a>&quot;. They are the best people out there to perform the tasks they perform to create your pastry, giving it the greatest value. And they just love to make their specialized pastry skill better and better until perfection.</p>\n\n"\
183
+ "<p>Of course, there is a workshop in each <em>Les Bonnes Choses</em> store, and every pastry you buy was made today, by the best pastry specialists in your country.</p>\n\n"\
184
+ "<p>However, the very difficult art of creating new concepts, juggling with tastes and creating brand new, powerful experiences, is performed every few months, during our &quot;<a href=\"http://localhost/UlfoxUnM0wkXYXbl\">Pastry Art Brainstorms</a>&quot;. During the event, the best pastry artists in the world (some working for <em>Les Bonnes Choses</em>, some not) gather in Paris, and showcase the experiments they've been working on; then, the other present artists comment on the piece, and iterate on it together, in order to make it the best possible masterchief!</p>\n\n"\
185
+ "<p>The session is presided by Jean-Michel Pastranova, who then selects the most delightful experiences, to add it to <em>Les Bonnes Choses</em>'s catalogue.</p>"
135
186
  end
136
187
  it "returns a correct as_text on a StructuredText" do
137
188
  @api.form("everything")
data/spec/prismic_spec.rb CHANGED
@@ -521,7 +521,8 @@ describe 'SearchForm' do
521
521
  "license":"All Rights Reserved"
522
522
  }
523
523
  DATA
524
- @api.form("everything").page_size('1').submit_raw(@master_ref).should == data
524
+ rx = Regexp.escape(data).sub(/"version":"[^"]+"/, '"version":"[^"]+"')
525
+ @api.form("everything").page_size('1').submit_raw(@master_ref).should =~ /#{rx}/
525
526
  end
526
527
  end
527
528
  end
@@ -1,30 +1,31 @@
1
1
  {
2
- "type": "StructuredText",
3
- "value": [{
4
- "type": "paragraph",
5
- "text": "Experience the ultimate vanilla experience. Our vanilla Macarons are made with our very own (in-house) pure extract of Madagascar vanilla, and subtly dusted with our own vanilla sugar (which we make from real vanilla beans).",
6
- "spans": [
7
- {
8
- "start": 103,
9
- "end": 137,
10
- "type": "em"
11
- },
12
- {
13
- "start": 11,
14
- "end": 14,
15
- "type": "hyperlink",
16
- "data": {
17
- "type": "Link.web",
18
- "value": {
19
- "url": "http://prismic.io"
20
- }
21
- }
22
- },
23
- {
24
- "start": 162,
25
- "end": 183,
26
- "type": "strong"
27
- }
28
- ]}
29
- ]
2
+ "type": "StructuredText",
3
+ "value": [{
4
+ "type": "paragraph",
5
+ "label": "vanilla",
6
+ "text": "Experience the ultimate vanilla experience. Our vanilla Macarons are made with our very own (in-house) pure extract of Madagascar vanilla, and subtly dusted with our own vanilla sugar (which we make from real vanilla beans).",
7
+ "spans": [
8
+ {
9
+ "start": 103,
10
+ "end": 137,
11
+ "type": "em"
12
+ },
13
+ {
14
+ "start": 11,
15
+ "end": 14,
16
+ "type": "hyperlink",
17
+ "data": {
18
+ "type": "Link.web",
19
+ "value": {
20
+ "url": "http://prismic.io"
21
+ }
22
+ }
23
+ },
24
+ {
25
+ "start": 162,
26
+ "end": 183,
27
+ "type": "strong"
28
+ }
29
+ ]
30
+ }]
30
31
  }
@@ -0,0 +1,156 @@
1
+ {
2
+ "type":"StructuredText",
3
+ "value":[
4
+ {
5
+ "type":"heading1",
6
+ "text":"Tips to dress a pastry",
7
+ "spans":[]
8
+ },
9
+ {
10
+ "type":"image",
11
+ "url":"https://prismic-io.s3.amazonaws.com/lesbonneschoses-vcerzcwaaohojzo/381f3a78dfe952b229fb49ceaa9926f7009ae20a.jpg",
12
+ "alt":"",
13
+ "copyright":"",
14
+ "dimensions":{
15
+ "width":640,
16
+ "height":666
17
+ }
18
+ },
19
+ {
20
+ "type":"paragraph",
21
+ "text":"Our Pastry Dressers (yes, it is a full-time job in Les Bonnes Choses!) have it somewhat different from our other pastry artists: while the others keep their main focus on the taste, smell, and potentially touch of your pastries, the Pastry Dressers are mainly focused on their looks.",
22
+ "spans":[
23
+ {
24
+ "start":32,
25
+ "end":47,
26
+ "type":"hyperlink",
27
+ "data":{
28
+ "type":"Link.document",
29
+ "value":{
30
+ "document":{
31
+ "id":"UlfoxUnM0wkXYXbh",
32
+ "type":"job-offer",
33
+ "tags":[],
34
+ "slug":"pastry-dresser"
35
+ },
36
+ "isBroken":false
37
+ }
38
+ }
39
+ },
40
+ {
41
+ "start":51,
42
+ "end":68,
43
+ "type":"em"
44
+ }
45
+ ]
46
+ },
47
+ {
48
+ "type":"paragraph",
49
+ "text":"It sometimes makes them feem like they're doing a job that is reasonably different from plain old pastry, and to make the most of your pastry dressings, perhaps so should you!",
50
+ "spans":[]
51
+ },
52
+ {
53
+ "type":"heading2",
54
+ "text":"Step by step",
55
+ "spans":[]
56
+ },
57
+ {
58
+ "type":"paragraph",
59
+ "text":"From bottom to top, the steps towards a great dressing are pretty clear, and change rarely.",
60
+ "spans":[]
61
+ },
62
+ {
63
+ "type":"heading3",
64
+ "text":"Pastry Dresser, or speleologist?",
65
+ "spans":[]
66
+ },
67
+ {
68
+ "type":"paragraph",
69
+ "text":"One of the first handy phases of dressing your pastry will be about carving to get to a desired shape and size to build upon. This is very precise work, as you will need to clean the object without breaking it, to remove pieces of it while keeping intact the meaningful bits. Now you're ready to iterate upon it!",
70
+ "spans":[
71
+ {
72
+ "start":173,
73
+ "end":178,
74
+ "type":"label",
75
+ "data":{
76
+ "label":"author"
77
+ }
78
+ }
79
+ ]
80
+ },
81
+ {
82
+ "type":"heading3",
83
+ "text":"Pastry Dresser, or clay sculptor?",
84
+ "spans":[]
85
+ },
86
+ {
87
+ "type":"paragraph",
88
+ "text":"Then, you will need to shape your piece of art into the design you have in mind, by adding the right materials to just the right places. Ganache is your friend in such moments, such as any shape-free material. You'll have to master them, so they obey to the shapes you have in mind.",
89
+ "spans":[
90
+ {
91
+ "start":47,
92
+ "end":51,
93
+ "type":"label",
94
+ "data":{
95
+ "label":"author"
96
+ }
97
+ },
98
+ {
99
+ "start":47,
100
+ "end":51,
101
+ "type":"strong"
102
+ }
103
+ ]
104
+ },
105
+ {
106
+ "type":"heading3",
107
+ "text":"Pastry Dresser, or hairdresser?",
108
+ "spans":[]
109
+ },
110
+ {
111
+ "type":"paragraph",
112
+ "text":"The top of the pastry is a priority zone for finalization. This is where your \"last touch\" goes, and it's tremendously important, as it gives the pastry most of its character. You will have to play with the details, to keep the top of your piece on the... top of your priorities!",
113
+ "spans":[]
114
+ },
115
+ {
116
+ "type":"heading2",
117
+ "text":"Before starting",
118
+ "spans":[]
119
+ },
120
+ {
121
+ "type":"paragraph",
122
+ "text":"Finishing by the beginning: what did we have to consider, before running towards the aforementioned steps?",
123
+ "spans":[]
124
+ },
125
+ {
126
+ "type":"image",
127
+ "url":"https://prismic-io.s3.amazonaws.com/lesbonneschoses-vcerzcwaaohojzo/502ebb427b5eb45693800816fc778316c04935f5.jpg",
128
+ "alt":"",
129
+ "copyright":"",
130
+ "dimensions":{
131
+ "width":640,
132
+ "height":427
133
+ }
134
+ },
135
+ {
136
+ "type":"heading3",
137
+ "text":"Pastry Dresser, or illustrator?",
138
+ "spans":[]
139
+ },
140
+ {
141
+ "type":"paragraph",
142
+ "text":"We didn't mention color, but it's a very important component of the piece. Just like an illustrator will pick colors that add to the shape in a matching way to keep a perfect meaning, the colors must be perfect to be consistent with the taste of the piece (do not use green-colored sugar for a strawberry-flavored pastry, if you don't want to gross people out!)",
143
+ "spans":[]
144
+ },
145
+ {
146
+ "type":"heading3",
147
+ "text":"Pastry Dresser, or designer?",
148
+ "spans":[]
149
+ },
150
+ {
151
+ "type":"paragraph",
152
+ "text":"And even before the illustration and colors, you really need to take the time to think about your destination, to make sure it's nothing short of perfect. This may imply taking the time to sit down for a few minutes with a paper and a pen. The first skill of an imaginative Pastry Dresser is a drawing skill, just like a fashion stylist.",
153
+ "spans":[]
154
+ }
155
+ ]
156
+ }
data/spec/spec_helper.rb CHANGED
@@ -8,6 +8,11 @@ rescue LoadError
8
8
  end
9
9
  require 'simplecov'
10
10
 
11
+ RSpec.configure do |c|
12
+ # Stop after the first failure
13
+ c.fail_fast = true
14
+ end
15
+
11
16
  SimpleCov.start
12
17
 
13
18
  $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
metadata CHANGED
@@ -1,71 +1,72 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prismic.io
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc10
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
- - "Étienne Vallette d'Osia"
7
+ - Étienne Vallette d'Osia
8
+ - Erwan Loisant
8
9
  - Samy Dindane
9
10
  - Rudy Rigot
10
11
  autorequire:
11
12
  bindir: bin
12
13
  cert_chain: []
13
- date: 2014-09-10 00:00:00.000000000 Z
14
+ date: 2014-09-23 00:00:00.000000000 Z
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
16
17
  name: bundler
17
18
  requirement: !ruby/object:Gem::Requirement
18
19
  requirements:
19
- - - "~>"
20
+ - - ~>
20
21
  - !ruby/object:Gem::Version
21
22
  version: '1.3'
22
23
  type: :development
23
24
  prerelease: false
24
25
  version_requirements: !ruby/object:Gem::Requirement
25
26
  requirements:
26
- - - "~>"
27
+ - - ~>
27
28
  - !ruby/object:Gem::Version
28
29
  version: '1.3'
29
30
  - !ruby/object:Gem::Dependency
30
31
  name: rspec
31
32
  requirement: !ruby/object:Gem::Requirement
32
33
  requirements:
33
- - - "~>"
34
+ - - ~>
34
35
  - !ruby/object:Gem::Version
35
36
  version: '2.14'
36
37
  type: :development
37
38
  prerelease: false
38
39
  version_requirements: !ruby/object:Gem::Requirement
39
40
  requirements:
40
- - - "~>"
41
+ - - ~>
41
42
  - !ruby/object:Gem::Version
42
43
  version: '2.14'
43
44
  - !ruby/object:Gem::Dependency
44
45
  name: nokogiri
45
46
  requirement: !ruby/object:Gem::Requirement
46
47
  requirements:
47
- - - "~>"
48
+ - - ~>
48
49
  - !ruby/object:Gem::Version
49
50
  version: '1.6'
50
51
  type: :development
51
52
  prerelease: false
52
53
  version_requirements: !ruby/object:Gem::Requirement
53
54
  requirements:
54
- - - "~>"
55
+ - - ~>
55
56
  - !ruby/object:Gem::Version
56
57
  version: '1.6'
57
58
  - !ruby/object:Gem::Dependency
58
59
  name: simplecov
59
60
  requirement: !ruby/object:Gem::Requirement
60
61
  requirements:
61
- - - "~>"
62
+ - - ~>
62
63
  - !ruby/object:Gem::Version
63
64
  version: '0.7'
64
65
  type: :development
65
66
  prerelease: false
66
67
  version_requirements: !ruby/object:Gem::Requirement
67
68
  requirements:
68
- - - "~>"
69
+ - - ~>
69
70
  - !ruby/object:Gem::Version
70
71
  version: '0.7'
71
72
  description: The standard Prismic.io's API library.
@@ -75,9 +76,10 @@ executables: []
75
76
  extensions: []
76
77
  extra_rdoc_files: []
77
78
  files:
78
- - ".gitignore"
79
- - ".travis.yml"
80
- - ".yardopts"
79
+ - .gitignore
80
+ - .travis.yml
81
+ - .yardopts
82
+ - Changelog.md
81
83
  - Gemfile
82
84
  - Gemfile.lock
83
85
  - README.md
@@ -119,6 +121,7 @@ files:
119
121
  - spec/responses_mocks/structured_text_heading.json
120
122
  - spec/responses_mocks/structured_text_linkfile.json
121
123
  - spec/responses_mocks/structured_text_paragraph.json
124
+ - spec/responses_mocks/structured_text_with_labels.json
122
125
  - spec/responses_mocks/structured_text_with_tricky_spans.json
123
126
  - spec/spec_helper.rb
124
127
  homepage: http://prismic.io
@@ -131,14 +134,14 @@ require_paths:
131
134
  - lib
132
135
  required_ruby_version: !ruby/object:Gem::Requirement
133
136
  requirements:
134
- - - ">="
137
+ - - '>='
135
138
  - !ruby/object:Gem::Version
136
139
  version: '0'
137
140
  required_rubygems_version: !ruby/object:Gem::Requirement
138
141
  requirements:
139
- - - ">"
142
+ - - '>='
140
143
  - !ruby/object:Gem::Version
141
- version: 1.3.1
144
+ version: '0'
142
145
  requirements: []
143
146
  rubyforge_project:
144
147
  rubygems_version: 2.2.2
@@ -160,5 +163,6 @@ test_files:
160
163
  - spec/responses_mocks/structured_text_heading.json
161
164
  - spec/responses_mocks/structured_text_linkfile.json
162
165
  - spec/responses_mocks/structured_text_paragraph.json
166
+ - spec/responses_mocks/structured_text_with_labels.json
163
167
  - spec/responses_mocks/structured_text_with_tricky_spans.json
164
168
  - spec/spec_helper.rb