prismic.io 1.0.0.rc6 → 1.0.0.rc7

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: 8f817e26c9531dedb21f23cae69edbcf8f5a1f77
4
- data.tar.gz: 41cd13bd44d6a052b0e770f138b6d70cf799b21e
3
+ metadata.gz: dc69199255c2d6ef198403766b9bc0d54ab2b36e
4
+ data.tar.gz: 1613eaab5156a26ab56fdd2f2470dc3009256bd0
5
5
  SHA512:
6
- metadata.gz: 4cbfe1c5347987bd16de9c244d4d89c13bf2ea2a79315e3094215ec63a5aa9f2ba20936701e92d6aa7c6cb74291421b958b7bb785aed03845914d19fb0f7c5d8
7
- data.tar.gz: 63767dc468b7a7f93c1bc8b4b1afcf4bedac8bf839dd4e8480e1f56cbabc1bf04ef999f565be4efaf10d477a114d1a63195cb86ffc48c90712bb20de07dbc689
6
+ metadata.gz: 9abb44957fddcea4d59a4526ab212d139921b9518eab7aa0038aaeaf3a982dbd4c55bab6f398927c372ceca0d9c6faad5822e8d5ffc18bae01f95947946fae9a
7
+ data.tar.gz: 28eef0cc87ca7504d0ec0fee7fc9ba05f02ca8bf50724627317918fb45b782047119d7c672f3885f0c4319cdc1c44de54bfb393d22f255305f33532e2001bc76
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ --markup markdown
2
+
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prismic.io (1.0.0.rc6)
4
+ prismic.io (1.0.0.rc7)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/lib/prismic.rb CHANGED
@@ -49,6 +49,8 @@ module Prismic
49
49
  # @param [String] url The URL of the prismic.io repository
50
50
  # @param [String] access_token The access token
51
51
  #
52
+ # @raise PrismicWSConnectionError
53
+ #
52
54
  # @return [API] The API instance related to this repository
53
55
  def self.api(url, opts=nil)
54
56
  opts ||= {}
@@ -56,23 +58,54 @@ module Prismic
56
58
  API.start(url, opts)
57
59
  end
58
60
 
61
+ # Build the URL where the user can be redirected to authenticated himself
62
+ # using OAuth2.
63
+ # @api
64
+ #
65
+ # @note: The endpoint depends on the repository, so an API call is made to
66
+ # fetch it.
67
+ #
68
+ # @param url[String] The URL of the prismic.io repository
69
+ # @param oauth_opts [Hash] The OAuth2 options
70
+ # @param api_opts [Hash] The API options (the same than accepted by the {api}
71
+ # method)
72
+ #
73
+ # @option oauth_opts :client_id [String] The Application's client ID
74
+ # @option oauth_opts :redirect_uri [String] The Application's secret
75
+ # @option oauth_opts :scope [String] The desired scope
76
+ #
77
+ # @raise PrismicWSConnectionError
78
+ #
79
+ # @return [String] The built URL
59
80
  def self.oauth_initiate_url(url, oauth_opts, api_opts=nil)
60
81
  api_opts ||= {}
61
82
  api_opts = {access_token: api_opts} if api_opts.is_a?(String)
62
83
  API.oauth_initiate_url(url, oauth_opts, api_opts)
63
84
  end
64
85
 
86
+ # Check a token and return an access_token
87
+ #
88
+ # This method allows to check the token received when the user has been
89
+ # redirected from the OAuth2 server. It returns an access_token that can
90
+ # be used to authenticate the user on the API.
91
+ #
92
+ # @param url [String] The URL of the prismic.io repository
93
+ # @param oauth_opts [Hash] The OAuth2 options
94
+ # @param api_opts [Hash] The API options (the same than accepted by the
95
+ # {api} method)
96
+ #
97
+ # @option oauth_opts :client_id [String] The Application's client ID
98
+ # @option oauth_opts :redirect_uri [String] The Application's secret
99
+ #
100
+ # @raise PrismicWSConnectionError
101
+ #
102
+ # @return [String] the access_token
65
103
  def self.oauth_check_token(url, oauth_opts, api_opts=nil)
66
104
  api_opts ||= {}
67
105
  api_opts = {access_token: api_opts} if api_opts.is_a?(String)
68
106
  API.oauth_check_token(url, oauth_opts, api_opts)
69
107
  end
70
108
 
71
- class ApiData
72
- attr_accessor :refs, :bookmarks, :types, :tags, :forms
73
- end
74
-
75
-
76
109
  # A SearchForm represent a Form returned by the prismic.io API.
77
110
  #
78
111
  # These forms depend on the prismic.io repository, and can be filled and sent
@@ -82,6 +115,7 @@ module Prismic
82
115
  #
83
116
  # The SearchForm instance contains helper methods for each predefined form's fields.
84
117
  # Note that these methods are not created if they risk to add confusion:
118
+ #
85
119
  # - only letters, underscore and digits are authorized in the name
86
120
  # - name starting with a digit or an underscore are forbidden
87
121
  # - generated method can't override existing methods
@@ -121,7 +155,6 @@ module Prismic
121
155
  # @return [SearchForm] self
122
156
 
123
157
  # @!method page_size(page_size)
124
- # @generated
125
158
  # Specify a page size for this form.
126
159
  # @param page_size [String,Fixum] The page size
127
160
  # @return [SearchForm] self
@@ -141,26 +174,44 @@ module Prismic
141
174
  end
142
175
  private :create_field_helper_method
143
176
 
177
+ # Returns the form's name
178
+ #
179
+ # @return [String]
144
180
  def form_name
145
181
  form.name
146
182
  end
147
183
 
184
+ # Returns the form's HTTP method
185
+ #
186
+ # @return [String]
148
187
  def form_method
149
188
  form.form_method
150
189
  end
151
190
 
191
+ # Returns the form's relationship
192
+ #
193
+ # @return [String]
152
194
  def form_rel
153
195
  form.rel
154
196
  end
155
197
 
198
+ # Returns the form's encoding type
199
+ #
200
+ # @return [String]
156
201
  def form_enctype
157
202
  form.enctype
158
203
  end
159
204
 
205
+ # Returns the form's action (URL)
206
+ #
207
+ # @return [String]
160
208
  def form_action
161
209
  form.action
162
210
  end
163
211
 
212
+ # Returns the form's fields
213
+ #
214
+ # @return [String]
164
215
  def form_fields
165
216
  form.fields
166
217
  end
@@ -168,15 +219,20 @@ module Prismic
168
219
  # Submit the form
169
220
  # @api
170
221
  #
171
- # @note The reference MUST be defined, either by setting it at
172
- # {API#create_search_form creation}, by using the {#ref} method or by
173
- # providing the ref parameter.
222
+ # @note The reference MUST be defined, either by:
223
+ #
224
+ # - setting it at {API#create_search_form creation}
225
+ # - using the {#ref} method
226
+ # - providing the ref parameter.
174
227
  #
175
- # @param ref [Ref, String] The {Ref reference} to use (if not already defined)
228
+ # @param ref [Ref, String] The {Ref reference} to use (if not already
229
+ # defined)
176
230
  #
177
- # @return [Documents] The results (array of Document object + pagination specifics)
231
+ # @return [Documents] The results (array of Document object + pagination
232
+ # specifics)
178
233
  def submit(ref = nil)
179
234
  self.ref(ref) if ref
235
+ data['ref'] = @ref
180
236
  raise NoRefSetException unless @ref
181
237
 
182
238
  # cache_key is a mix of HTTP URL and HTTP method
@@ -184,7 +240,6 @@ module Prismic
184
240
 
185
241
  api.caching(cache_key) {
186
242
  if form_method == "GET" && form_enctype == "application/x-www-form-urlencoded"
187
- data['ref'] = @ref
188
243
  data['access_token'] = api.access_token if api.access_token
189
244
  data.delete_if { |k, v| v.nil? }
190
245
 
@@ -270,12 +325,22 @@ module Prismic
270
325
  def [](i)
271
326
  @results[i]
272
327
  end
328
+ alias :get :[]
273
329
 
330
+ # Iterates over received documents
331
+ #
332
+ # @yieldparam document [Document]
333
+ #
334
+ # This method _does not_ paginates by itself. So only the received document
335
+ # will be returned.
274
336
  def each(&blk)
275
337
  @results.each(&blk)
276
338
  end
277
339
  include Enumerable # adds map, select, etc
278
340
 
341
+ # Return the number of returned documents
342
+ #
343
+ # @return [Fixum]
279
344
  def length
280
345
  @results.length
281
346
  end
@@ -294,20 +359,31 @@ module Prismic
294
359
  @fragments = (fragments.is_a? Hash) ? parse_fragments(fragments) : fragments
295
360
  end
296
361
 
362
+ # Returns the document's slug
363
+ #
364
+ # @return [String]
297
365
  def slug
298
366
  slugs.empty? ? '-' : slugs.first
299
367
  end
300
368
 
369
+ # Generate an HTML representation of the entire document
370
+ #
371
+ # @param link_resolver [LinkResolver] The LinkResolver used to build
372
+ # application's specific URL
373
+ #
374
+ # @return [String] the HTML representation
301
375
  def as_html(link_resolver)
302
376
  fragments.map { |field, fragment|
303
377
  %(<section data-field="#{field}">#{fragment.as_html(link_resolver)}</section>)
304
378
  }.join("\n")
305
379
  end
306
380
 
307
- # Finds the first highest title in a document
381
+ # Finds the first highest title in a document (if any)
308
382
  #
309
- # It is impossible to reuse the StructuredText.first_title method, since we need to test the highest title across the whole document
383
+ # @return [String]
310
384
  def first_title
385
+ # It is impossible to reuse the StructuredText.first_title method, since
386
+ # we need to test the highest title across the whole document
311
387
  title = false
312
388
  max_level = 6 # any title with a higher level kicks the current one out
313
389
  @fragments.each do |_, fragment|
@@ -325,12 +401,16 @@ module Prismic
325
401
  title
326
402
  end
327
403
 
404
+ # Get a document's field
328
405
  def [](field)
329
406
  array = field.split('.')
330
- raise ArgumentError, "Argument should contain one dot. Example: product.price" if array.length != 2
407
+ if array.length != 2
408
+ raise ArgumentError, "Argument should contain one dot. Example: product.price"
409
+ end
331
410
  return nil if array[0] != self.type
332
411
  fragments[array[1]]
333
412
  end
413
+ alias :get :[]
334
414
 
335
415
  private
336
416
 
@@ -346,7 +426,26 @@ module Prismic
346
426
  # (except /api) and allow to assert that the URL you use will always
347
427
  # returns the same results.
348
428
  class Ref
349
- attr_accessor :ref, :label, :is_master, :scheduled_at
429
+
430
+ # Returns the value of attribute ref.
431
+ #
432
+ # @return [String]
433
+ attr_accessor :ref
434
+
435
+ # Returns the value of attribute label.
436
+ #
437
+ # @return [String]
438
+ attr_accessor :label
439
+
440
+ # Returns the value of attribute is_master.
441
+ #
442
+ # @return [Boolean]
443
+ attr_accessor :is_master
444
+
445
+ # Returns the value of attribute scheduled_at.
446
+ #
447
+ # @return [Time]
448
+ attr_accessor :scheduled_at
350
449
 
351
450
  def initialize(ref, label, is_master = false, scheduled_at = nil)
352
451
  @ref = ref
@@ -358,8 +457,13 @@ module Prismic
358
457
  alias :master? :is_master
359
458
  end
360
459
 
460
+ # The LinkResolver will help to build URL specific to an application, based
461
+ # on a generic prismic.io's {Fragments::DocumentLink Document link}.
361
462
  class LinkResolver
362
463
  attr_reader :ref
464
+
465
+ # @yieldparam doc_link [Fragments::DocumentLink] A DocumentLink instance
466
+ # @yieldreturn [String] The application specific URL of the given document
363
467
  def initialize(ref, &blk)
364
468
  @ref = ref
365
469
  @blk = blk
@@ -431,11 +535,11 @@ module Prismic
431
535
  # The {LinkResolver} will help to build URL specific to an application, based
432
536
  # on a generic prismic.io's {Fragments::DocumentLink Document link}.
433
537
  #
434
- # @param ref [Ref] The ref to use
435
- # @yieldparam doc_link [Fragments::DocumentLink] A DocumentLink instance
538
+ # @param ref [Ref] The ref to use
539
+ # @yieldparam doc_link [Fragments::DocumentLink] A DocumentLink instance
436
540
  # @yieldreturn [String] The application specific URL of the given document
437
541
  #
438
- # @return [LinkResolver] [description]
542
+ # @return [LinkResolver] the {LinkResolver} instance
439
543
  def self.link_resolver(ref, &blk)
440
544
  LinkResolver.new(ref, &blk)
441
545
  end
data/lib/prismic/api.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Prismic
4
+ # The API is the main class
4
5
  class API
5
- @@cache = nil
6
6
  @@warned_create_search_form = false
7
7
  @@warned_oauth_initiate_url = false
8
8
  @@warned_oauth_check_token = false
@@ -21,6 +21,7 @@ module Prismic
21
21
  # If the cache is disabled, the block is always called
22
22
  #
23
23
  # @param key [String] the cache's key to test
24
+ # @yieldparam key [String] the key
24
25
  #
25
26
  # @return the return of the given block
26
27
  def caching(key)
data/lib/prismic/cache.rb CHANGED
@@ -1,24 +1,30 @@
1
1
  # encoding: utf-8
2
2
  module Prismic
3
3
  # This is a simple cache class provided with the prismic.io Ruby kit.
4
+ #
4
5
  # It is pretty dumb but effective:
5
- # * everything is stored in memory,
6
- # * invalidation: not needed for prismic.io documents (they are eternally immutable), but we don't want the cache to expand indefinitely; therefore all cache but the new master ref is cleared when a new master ref gets published.
7
6
  #
8
- # If you need a smarter caching (for instance, caching in files), you can extend this class and replace its methods,
9
- # and when creating your API object like this for instance: Prismic.api(url, options), pass the name of the class you created
10
- # as a :cache option.
11
- # Therefore, to use this simple cache, you can create your API object like this: Prismic.api(url, cache: Prismic::DefaultCache)
7
+ # * everything is stored in memory,
8
+ # * invalidation: not needed for prismic.io documents (they are eternally
9
+ # immutable), but we don't want the cache to expand indefinitely; therefore
10
+ # all cache but the new master ref is cleared when a new master ref gets
11
+ # published.
12
+ #
13
+ # If you need a smarter caching (for instance, caching in files), you can
14
+ # extend this class and replace its methods, and when creating your API object
15
+ # like this for instance: Prismic.api(url, options), pass the name of the
16
+ # class you created as a :cache option. Therefore, to use this simple cache,
17
+ # you can create your API object like this: `Prismic.api(url, cache:
18
+ # Prismic::DefaultCache)`
12
19
  class Cache
13
20
 
14
21
  # Based on http://stackoverflow.com/questions/1933866/efficient-ruby-lru-cache
15
22
  # The Hash are sorted, so the age is represented by the key order
16
23
 
17
- # Returns the cache object holding the responses to "results" queries (lists of documents).
18
- # This is a Hash in a Hash: keys in the outer Hash are the refs (so that it's easy to invalidate entire refs at once);
19
- # keys in the inner Hash are the query strings (URLs) of each query.
20
- # The object that is stored as a cache_object is what is returned by Prismic::JsonParser::results_parser
21
- # (so that we don't have to parse anything again, it's stored already parsed).
24
+ # Returns the cache object holding the responses to "results" queries (lists
25
+ # of documents). The object that is stored as a cache_object is what is
26
+ # returned by {Prismic::JsonParser.results_parser} (so that we don't have to
27
+ # parse anything again, it's stored already parsed).
22
28
  #
23
29
  # @return [Hash<String,Object>]
24
30
  attr_reader :intern
@@ -36,10 +42,10 @@ module Prismic
36
42
 
37
43
  # Add a cache entry.
38
44
  #
39
- # @param key [String] the key
40
- # @param value the value to store
45
+ # @param key [String] The key
46
+ # @param value [Object] The value to store
41
47
  #
42
- # @return the value
48
+ # @return [Object] The stored value
43
49
  def store(key, value)
44
50
  @intern.delete(key)
45
51
  @intern[key] = value
@@ -55,7 +61,7 @@ module Prismic
55
61
  # Prune the cache old oldest keys if the new max_size is older than the keys
56
62
  # number.
57
63
  #
58
- # @param max_size [Fixnum] the new maximun number of keys to store
64
+ # @param max_size [Fixnum] The new maximun number of keys to store
59
65
  def max_size=(max_size)
60
66
  raise ArgumentError.new(:max_size) if max_size < 1
61
67
  @max_size = max_size
@@ -71,9 +77,9 @@ module Prismic
71
77
  # A block can be provided: it will be used to compute (and store) the value
72
78
  # if the key is missing.
73
79
  #
74
- # @param key [String] the key to fetch
80
+ # @param key [String] The key to fetch
75
81
  #
76
- # @return [Object] the cache object as was stored
82
+ # @return [Object] The cache object as was stored
77
83
  def get(key)
78
84
  found = true
79
85
  value = @intern.delete(key){ found = false }
@@ -87,22 +93,22 @@ module Prismic
87
93
 
88
94
  # Checks if a cache entry exists
89
95
  #
90
- # @param key [String] the key to test
96
+ # @param key [String] The key to test
91
97
  #
92
98
  # @return [Boolean]
93
99
  def include?(key)
94
100
  @intern.include?(key)
95
101
  end
96
102
 
97
- # Invalidates all the cache
103
+ # Invalidates all entries
98
104
  def invalidate_all!
99
105
  @intern.clear
100
106
  end
101
107
  alias :clear! :invalidate_all!
102
108
 
103
- # Expose a Hash of the keys of both Hashes. The keys of this Hash is the ref_ids, the values are arrays of cache_keys.
104
- # This is only for displaying purposes, if you want to check out what's stored in your cache without checking out the
105
- # quite verbose cache_objects.
109
+ # Expose the Hash keys
110
+ #
111
+ # This is only for debugging purposes.
106
112
  #
107
113
  # @return [Array<String>]
108
114
  def keys
@@ -119,5 +125,7 @@ module Prismic
119
125
 
120
126
  end
121
127
 
128
+ # This default instance is used by the API to avoid creating a new instance
129
+ # per request (which would make the cache useless).
122
130
  DefaultCache = Cache.new
123
131
  end
@@ -8,6 +8,12 @@ module Prismic
8
8
  @value = value
9
9
  end
10
10
 
11
+ # Returns the RGB values in a Hash
12
+ #
13
+ # @example
14
+ # color.asRGB # => {'red' => 123, 'green' => 123, 'blue' => 123}
15
+ #
16
+ # @return [Hash]
11
17
  def asRGB
12
18
  Fragments::Color.asRGB(@value)
13
19
  end
@@ -20,6 +26,12 @@ module Prismic
20
26
  }
21
27
  end
22
28
 
29
+ # Generate an HTML representation of the fragment
30
+ #
31
+ # @param link_resolver [LinkResolver] The LinkResolver used to build
32
+ # application's specific URL
33
+ #
34
+ # @return [String] the HTML representation
23
35
  def as_html(link_resolver=nil)
24
36
  %(<span class="color">##@value</span>)
25
37
  end
@@ -8,6 +8,12 @@ module Prismic
8
8
  @value = value
9
9
  end
10
10
 
11
+ # Generate an HTML representation of the fragment
12
+ #
13
+ # @param link_resolver [LinkResolver] The LinkResolver used to build
14
+ # application's specific URL
15
+ #
16
+ # @return [String] the HTML representation
11
17
  def as_html(link_resolver=nil)
12
18
  %(<time>#{value.iso8601(3)}</time>)
13
19
  end
@@ -12,6 +12,12 @@ module Prismic
12
12
  @o_embed_json = o_embed_json
13
13
  end
14
14
 
15
+ # Generate an HTML representation of the fragment
16
+ #
17
+ # @param link_resolver [LinkResolver] The LinkResolver used to build
18
+ # application's specific URL
19
+ #
20
+ # @return [String] the HTML representation
15
21
  def as_html(link_resolver=nil)
16
22
  <<-HTML
17
23
  <div data-oembed="#@url"
@@ -1,22 +1,25 @@
1
1
  # encoding: utf-8
2
2
  module Prismic
3
- module Fragments
4
- # Generic fragment, this class is to be extended by all fragment classes.
5
- class Fragment
6
- # Generic as_html method for fragments, meant to be overriden by
7
- # specific fragment classes.
8
- #
9
- # @return [String] an empty string
10
- def as_html(link_resolver = nil)
11
- raise NotImplementedError, "Method #{__method__} is not implemented for #{inspect}", caller
12
- end
13
- # Generic as_text method for fragments, meant to be overriden by
14
- # specific fragment classes.
15
- #
16
- # @return [String] an empty string
17
- def as_text()
18
- raise NotImplementedError, "Method #{__method__} is not implemented for #{inspect}", caller
19
- end
20
- end
21
- end
3
+ module Fragments
4
+ # Generic fragment, this class is to be extended by all fragment classes.
5
+ class Fragment
6
+
7
+ # Generic as_html method for fragments, meant to be overriden by
8
+ # specific fragment classes.
9
+ #
10
+ # @return [String] an empty string
11
+ def as_html(link_resolver = nil)
12
+ raise NotImplementedError, "Method #{__method__} is not implemented for #{inspect}", caller
13
+ end
14
+
15
+ # Generic as_text method for fragments, meant to be overriden by
16
+ # specific fragment classes.
17
+ #
18
+ # @return [String] an empty string
19
+ def as_text()
20
+ raise NotImplementedError, "Method #{__method__} is not implemented for #{inspect}", caller
21
+ end
22
+
23
+ end
24
+ end
22
25
  end
@@ -1,78 +1,103 @@
1
1
  module Prismic
2
- module Fragments
3
-
4
- # A fragment of type Group, which contains an array of FragmentList (which itself is a Hash of fragments).
5
- #
6
- # For instance, imagining this group is defined with two possible fragments :
7
- # an image fragment "image", and a text fragment "caption";
8
- # then accessing the first image will look like this: group[0]['image'].
9
- class Group < Fragment
10
-
11
- # The array of the fragment lists
12
- attr_accessor :fragment_list_array
13
-
14
- def initialize(fragment_list_array)
15
- @fragment_list_array = fragment_list_array
16
- end
17
-
18
- # Accessing the i-th item (fragment list) of the group: group[i]
19
- def [](i)
20
- @fragment_list_array[i]
21
- end
22
-
23
- def each(&blk)
24
- @fragment_list_array.each(&blk)
25
- end
26
- include Enumerable # adds map, select, etc
27
-
28
- def length
29
- @fragment_list_array.length
30
- end
31
- alias :size :length
32
-
33
- def as_html(link_resolver = nil)
34
- @fragment_list_array.map { |fl| fl.as_html(link_resolver) }.join("\n")
35
- end
36
-
37
- def as_text
38
- @fragment_list_array.map { |fl| fl.as_text }.join("\n")
39
- end
40
-
41
-
42
- class FragmentMapping
43
-
44
- # a hash containing all the fragments in the fragment list
45
- attr_accessor :fragments
46
-
47
- def initialize(fragments)
48
- @fragments = fragments
49
- end
50
-
51
- # Accessing the right fragment of the fragment list: fl['caption']
52
- def [](name)
53
- @fragments[name]
54
- end
55
-
56
- def each(&blk)
57
- @fragments.each(&blk)
58
- end
59
- include Enumerable # adds map, select, etc
60
-
61
- def length
62
- @fragments.length
63
- end
64
- alias :size :length
65
-
66
- def as_html(link_resolver = nil)
67
- @fragments.map { |name, fragment|
68
- %(<section data-field="#{name}">#{fragment.as_html(link_resolver)}</section>)
69
- }.join("\n")
70
- end
71
-
72
- def as_text
73
- @fragments.values.map { |fragment| fragment.as_text }.join("\n")
74
- end
75
- end
76
- end
77
- end
2
+ module Fragments
3
+
4
+ # A fragment of type Group, which contains an array of FragmentList (which
5
+ # itself is a Hash of fragments).
6
+ #
7
+ # For instance, imagining this group is defined with two possible fragments:
8
+ # an image fragment "image", and a text fragment "caption"; then accessing
9
+ # the first image will look like this: `group[0]['image']`.
10
+ class Group < Fragment
11
+
12
+ # The array of the fragment lists
13
+ attr_accessor :fragment_list_array
14
+
15
+ def initialize(fragment_list_array)
16
+ @fragment_list_array = fragment_list_array
17
+ end
18
+
19
+ # Accessing the i-th item (fragment list) of the group: `group[i]`
20
+ def [](i)
21
+ @fragment_list_array[i]
22
+ end
23
+ alias :get :[]
24
+
25
+ # @yieldparam fragment [Fragment]
26
+ def each(&blk)
27
+ @fragment_list_array.each(&blk)
28
+ end
29
+ include Enumerable # adds map, select, etc
30
+
31
+ def length
32
+ @fragment_list_array.length
33
+ end
34
+ alias :size :length
35
+
36
+ # Generate an HTML representation of the group
37
+ #
38
+ # @param link_resolver [LinkResolver] The LinkResolver used to build
39
+ # application's specific URL
40
+ #
41
+ # @return [String] the HTML representation
42
+ def as_html(link_resolver = nil)
43
+ @fragment_list_array.map { |fl| fl.as_html(link_resolver) }.join("\n")
44
+ end
45
+
46
+ # Generate an text representation of the group
47
+ #
48
+ # @return [String] the text representation
49
+ def as_text
50
+ @fragment_list_array.map { |fl| fl.as_text }.join("\n")
51
+ end
52
+
53
+
54
+ class FragmentMapping
55
+
56
+ # a hash containing all the fragments in the fragment list
57
+ attr_accessor :fragments
58
+
59
+ def initialize(fragments)
60
+ @fragments = fragments
61
+ end
62
+
63
+ # Accessing the right fragment of the fragment list: `fl['caption']`
64
+ def [](name)
65
+ @fragments[name]
66
+ end
67
+ alias :get :[]
68
+
69
+ # @yieldparam name [String]
70
+ # @yieldparam fragment [Fragment]
71
+ def each(&blk)
72
+ @fragments.each(&blk)
73
+ end
74
+ include Enumerable # adds map, select, etc
75
+
76
+ # @return [Fixum]
77
+ def length
78
+ @fragments.length
79
+ end
80
+ alias :size :length
81
+
82
+ # Generate an HTML representation of the fragments
83
+ #
84
+ # @param link_resolver [LinkResolver] The LinkResolver used to build
85
+ # application's specific URL
86
+ #
87
+ # @return [String] the HTML representation
88
+ def as_html(link_resolver = nil)
89
+ @fragments.map { |name, fragment|
90
+ %(<section data-field="#{name}">#{fragment.as_html(link_resolver)}</section>)
91
+ }.join("\n")
92
+ end
93
+
94
+ # Generate a text representation of the fragment
95
+ #
96
+ # @return [String] the text representation
97
+ def as_text
98
+ @fragments.values.map { |fragment| fragment.as_text }.join("\n")
99
+ end
100
+ end
101
+ end
102
+ end
78
103
  end
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
  module Prismic
3
3
 
4
- VERSION = "1.0.0.rc6"
4
+ VERSION = "1.0.0.rc7"
5
5
 
6
6
  end
data/spec/cache_spec.rb CHANGED
@@ -69,5 +69,18 @@ describe "Cache's" do
69
69
  @cache.include?('fake_key2').should be_false
70
70
  end
71
71
  end
72
+
73
+ describe 'caching on a real repository' do
74
+ before do
75
+ @api = Prismic.api("https://lesbonneschoses.prismic.io/api", access_token: 'MC5VbDdXQmtuTTB6Z0hNWHF3.c--_vVbvv73vv73vv73vv71EA--_vS_vv73vv70T77-9Ke-_ve-_vWfvv70ebO-_ve-_ve-_vQN377-9ce-_vRfvv70')
76
+ @cache = @api.cache
77
+ @master_ref = @api.master_ref
78
+ @other_ref = @api.refs['announcement of new sf shop']
79
+ end
80
+ it 'works on different refs' do
81
+ @api.form('everything').submit(@master_ref).total_results_size.should == 40
82
+ @api.form('everything').submit(@other_ref).total_results_size.should == 43
83
+ end
84
+ end
72
85
  end
73
86
  end
@@ -2,148 +2,148 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe 'LesBonnesChoses' do
5
- before do
6
- @api = Prismic.api("https://lesbonneschoses.prismic.io/api", nil)
7
- @master_ref = @api.master_ref
8
- end
5
+ before do
6
+ @api = Prismic.api("https://lesbonneschoses.prismic.io/api", nil)
7
+ @master_ref = @api.master_ref
8
+ end
9
9
 
10
- describe '/api' do
11
- it "API works" do
12
- @api.should_not be_nil
13
- end
14
- end
10
+ describe '/api' do
11
+ it "API works" do
12
+ @api.should_not be_nil
13
+ end
14
+ end
15
15
 
16
- describe 'query' do
17
- it "queries everything and returns 20 documents" do
18
- @api.form("everything").submit(@master_ref).size.should == 20
19
- @api.form("everything").submit(@master_ref).results.size.should == 20
20
- end
16
+ describe 'query' do
17
+ it "queries everything and returns 20 documents" do
18
+ @api.form("everything").submit(@master_ref).size.should == 20
19
+ @api.form("everything").submit(@master_ref).results.size.should == 20
20
+ end
21
21
 
22
- it "queries macarons (using a predicate) and returns 7 documents" do
23
- @api.form("everything")
24
- .query(%([[:d = any(document.tags, ["Macaron"])]]))
25
- .submit(@master_ref).results.size.should == 7
26
- @api.form("everything")
27
- .query(%([[:d = any(document.tags, ["Macaron"])]]))
28
- .submit(@master_ref).size.should == 7
29
- end
22
+ it "queries macarons (using a predicate) and returns 7 documents" do
23
+ @api.form("everything")
24
+ .query(%([[:d = any(document.tags, ["Macaron"])]]))
25
+ .submit(@master_ref).results.size.should == 7
26
+ @api.form("everything")
27
+ .query(%([[:d = any(document.tags, ["Macaron"])]]))
28
+ .submit(@master_ref).size.should == 7
29
+ end
30
30
 
31
- it "queries macarons (using a form) and returns 7 documents" do
32
- @api.form("macarons").submit(@master_ref).results.size.should == 7
33
- @api.form("macarons").submit(@master_ref).size.should == 7
34
- end
31
+ it "queries macarons (using a form) and returns 7 documents" do
32
+ @api.form("macarons").submit(@master_ref).results.size.should == 7
33
+ @api.form("macarons").submit(@master_ref).size.should == 7
34
+ end
35
35
 
36
- it "queries macarons or cupcakes (using a form + a predicate) and returns 11 documents" do
37
- @api.form("products")
38
- .query(%([[:d = any(document.tags, ["Cupcake", "Macaron"])]]))
39
- .submit(@master_ref).results.size.should == 11
40
- @api.form("products")
41
- .query(%([[:d = any(document.tags, ["Cupcake", "Macaron"])]]))
42
- .submit(@master_ref).size.should == 11
43
- end
44
- end
36
+ it "queries macarons or cupcakes (using a form + a predicate) and returns 11 documents" do
37
+ @api.form("products")
38
+ .query(%([[:d = any(document.tags, ["Cupcake", "Macaron"])]]))
39
+ .submit(@master_ref).results.size.should == 11
40
+ @api.form("products")
41
+ .query(%([[:d = any(document.tags, ["Cupcake", "Macaron"])]]))
42
+ .submit(@master_ref).size.should == 11
43
+ end
44
+ end
45
45
 
46
- describe 'pagination' do
47
- it "works in basic cases" do
48
- documents = @api.form("everything").submit(@master_ref)
49
- documents.page.should == 1
50
- documents.results_per_page.should == 20
51
- documents.results_size.should == 20
52
- documents.total_results_size.should == 40
53
- documents.total_pages.should == 2
54
- documents.next_page.should == "https://lesbonneschoses.prismic.io/api/documents/search?ref=UkL0hcuvzYUANCrm&page=2&pageSize=20"
55
- documents.prev_page.should == nil
56
- end
57
- it "works on page 2" do
58
- documents = @api.form("everything").page("2").submit(@master_ref)
59
- documents.page.should == 2
60
- documents.results_per_page.should == 20
61
- documents.results_size.should == 20
62
- documents.total_results_size.should == 40
63
- documents.total_pages.should == 2
64
- documents.next_page.should == nil
65
- documents.prev_page.should == "https://lesbonneschoses.prismic.io/api/documents/search?ref=UkL0hcuvzYUANCrm&page=1&pageSize=20"
66
- end
67
- it "works on page 2 with a pagination step of 10" do
68
- documents = @api.form("everything").page("2").page_size("10").submit(@master_ref)
69
- documents.page.should == 2
70
- documents.results_per_page.should == 10
71
- documents.results_size.should == 10
72
- documents.total_results_size.should == 40
73
- documents.total_pages.should == 4
74
- documents.next_page.should == "https://lesbonneschoses.prismic.io/api/documents/search?ref=UkL0hcuvzYUANCrm&page=3&pageSize=10"
75
- documents.prev_page.should == "https://lesbonneschoses.prismic.io/api/documents/search?ref=UkL0hcuvzYUANCrm&page=1&pageSize=10"
76
- end
77
- end
46
+ describe 'pagination' do
47
+ it "works in basic cases" do
48
+ documents = @api.form("everything").submit(@master_ref)
49
+ documents.page.should == 1
50
+ documents.results_per_page.should == 20
51
+ documents.results_size.should == 20
52
+ documents.total_results_size.should == 40
53
+ documents.total_pages.should == 2
54
+ documents.next_page.should == "https://lesbonneschoses.prismic.io/api/documents/search?ref=UkL0hcuvzYUANCrm&page=2&pageSize=20"
55
+ documents.prev_page.should == nil
56
+ end
57
+ it "works on page 2" do
58
+ documents = @api.form("everything").page("2").submit(@master_ref)
59
+ documents.page.should == 2
60
+ documents.results_per_page.should == 20
61
+ documents.results_size.should == 20
62
+ documents.total_results_size.should == 40
63
+ documents.total_pages.should == 2
64
+ documents.next_page.should == nil
65
+ documents.prev_page.should == "https://lesbonneschoses.prismic.io/api/documents/search?ref=UkL0hcuvzYUANCrm&page=1&pageSize=20"
66
+ end
67
+ it "works on page 2 with a pagination step of 10" do
68
+ documents = @api.form("everything").page("2").page_size("10").submit(@master_ref)
69
+ documents.page.should == 2
70
+ documents.results_per_page.should == 10
71
+ documents.results_size.should == 10
72
+ documents.total_results_size.should == 40
73
+ documents.total_pages.should == 4
74
+ documents.next_page.should == "https://lesbonneschoses.prismic.io/api/documents/search?ref=UkL0hcuvzYUANCrm&page=3&pageSize=10"
75
+ documents.prev_page.should == "https://lesbonneschoses.prismic.io/api/documents/search?ref=UkL0hcuvzYUANCrm&page=1&pageSize=10"
76
+ end
77
+ end
78
78
 
79
- describe 'API::Document' do
80
- before do
81
- @document = @api.form('everything').query(%([[:d = at(document.id, "UkL0gMuvzYUANCpf")]])).submit(@master_ref)[0]
82
- end
79
+ describe 'API::Document' do
80
+ before do
81
+ @document = @api.form('everything').query(%([[:d = at(document.id, "UkL0gMuvzYUANCpf")]])).submit(@master_ref)[0]
82
+ end
83
83
 
84
- it 'Operator [] works on document' do
85
- @document['job-offer.name'].as_html(nil).should == '<h1>Pastry Dresser</h1>'
86
- end
84
+ it 'Operator [] works on document' do
85
+ @document['job-offer.name'].as_html(nil).should == '<h1>Pastry Dresser</h1>'
86
+ end
87
87
 
88
- it 'Operator [] returns nil if wrong type' do
89
- @document['product.name'].should == nil
90
- end
88
+ it 'Operator [] returns nil if wrong type' do
89
+ @document['product.name'].should == nil
90
+ end
91
91
 
92
- it 'Operator [] raises error if field is nonsense' do
93
- expect {
94
- @document['blablabla']
95
- }.to raise_error(ArgumentError, "Argument should contain one dot. Example: product.price")
96
- end
97
- end
92
+ it 'Operator [] raises error if field is nonsense' do
93
+ expect {
94
+ @document['blablabla']
95
+ }.to raise_error(ArgumentError, "Argument should contain one dot. Example: product.price")
96
+ end
97
+ end
98
98
 
99
- describe 'API::Documents' do
100
- before do
101
- @documents = @api.form('everything').submit(@master_ref)
102
- end
99
+ describe 'API::Documents' do
100
+ before do
101
+ @documents = @api.form('everything').submit(@master_ref)
102
+ end
103
103
 
104
- it 'has a working [] operator' do
105
- @documents[0].slug.should == @documents.results[0].slug
106
- end
107
- it 'has a proper size' do
108
- @documents.length.should == 20
109
- @documents.size.should == 20
110
- end
111
- it 'has a proper each method' do
112
- array = []
113
- @documents.each {|document| array << document.slug }
114
- array.join(' ').should == 'pastry-dresser exotic-kiwi-pie apricot-pie sweet-strawberry-pie woodland-cherry-pie cool-coconut-macaron salted-caramel-macaron the-end-of-a-chapter-the-beginning-of-a-new-one get-the-right-approach-to-ganache one-day-in-the-life-of-a-les-bonnes-choses-pastry les-bonnes-chosess-internship-a-testimony our-world-famous-pastry-art-brainstorm-event tips-to-dress-a-pastry triple-chocolate-cupcake dont-be-a-stranger about-us wedding-gift-box art-director store-intern content-director'
115
- end
116
- it 'is a proper Enumerable' do
117
- @documents.map {|document| document.slug }.join(' ').should == 'pastry-dresser exotic-kiwi-pie apricot-pie sweet-strawberry-pie woodland-cherry-pie cool-coconut-macaron salted-caramel-macaron the-end-of-a-chapter-the-beginning-of-a-new-one get-the-right-approach-to-ganache one-day-in-the-life-of-a-les-bonnes-choses-pastry les-bonnes-chosess-internship-a-testimony our-world-famous-pastry-art-brainstorm-event tips-to-dress-a-pastry triple-chocolate-cupcake dont-be-a-stranger about-us wedding-gift-box art-director store-intern content-director'
118
- end
119
- end
104
+ it 'has a working [] operator' do
105
+ @documents[0].slug.should == @documents.results[0].slug
106
+ end
107
+ it 'has a proper size' do
108
+ @documents.length.should == 20
109
+ @documents.size.should == 20
110
+ end
111
+ it 'has a proper each method' do
112
+ array = []
113
+ @documents.each {|document| array << document.slug }
114
+ array.join(' ').should == 'pastry-dresser exotic-kiwi-pie apricot-pie sweet-strawberry-pie woodland-cherry-pie cool-coconut-macaron salted-caramel-macaron the-end-of-a-chapter-the-beginning-of-a-new-one get-the-right-approach-to-ganache one-day-in-the-life-of-a-les-bonnes-choses-pastry les-bonnes-chosess-internship-a-testimony our-world-famous-pastry-art-brainstorm-event tips-to-dress-a-pastry triple-chocolate-cupcake dont-be-a-stranger about-us wedding-gift-box art-director store-intern content-director'
115
+ end
116
+ it 'is a proper Enumerable' do
117
+ @documents.map {|document| document.slug }.join(' ').should == 'pastry-dresser exotic-kiwi-pie apricot-pie sweet-strawberry-pie woodland-cherry-pie cool-coconut-macaron salted-caramel-macaron the-end-of-a-chapter-the-beginning-of-a-new-one get-the-right-approach-to-ganache one-day-in-the-life-of-a-les-bonnes-choses-pastry les-bonnes-chosess-internship-a-testimony our-world-famous-pastry-art-brainstorm-event tips-to-dress-a-pastry triple-chocolate-cupcake dont-be-a-stranger about-us wedding-gift-box art-director store-intern content-director'
118
+ end
119
+ end
120
120
 
121
- describe 'Fragments' do
122
- before do
123
- @link_resolver = Prismic.link_resolver("master"){|doc_link| "http://localhost/#{doc_link.id}" }
124
- end
125
- describe 'API::Fragments::StructuredText' do
126
- it "returns a correct as_html on a StructuredText with list, span, embed and image" do
127
- @api.form("everything")
128
- .query(%([[:d = at(document.id, "UkL0gMuvzYUANCpr")]]))
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"
130
- end
131
- it "returns a correct as_html on a StructuredText with links" do
132
- @api.form("everything")
133
- .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/UkL0gMuvzYUANCpa\">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/UkL0gMuvzYUANCpX\">a second shop on Paris's Champs-Élysées</a>, and <a href=\"http://localhost/UkL0gMuvzYUANCpY\">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/UkL0gMuvzYUANCpW\">New York</a> (2000) and <a href=\"http://localhost/UkL0gMuvzYUANCpZ\">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/UkL0gMuvzYUANCpe\">ganache specialists</a>&quot;, &quot;<a href=\"http://localhost/UkL0gMuvzYUANCpc\">fruit experts</a>&quot;, or &quot;<a href=\"http://localhost/UkL0gMuvzYUANCpb\">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/UkL0gMuvzYUANCpo\">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>"
135
- end
136
- it "returns a correct as_text on a StructuredText" do
137
- @api.form("everything")
138
- .query(%([[:d = at(document.id, "UkL0gMuvzYUANCps")]]))
139
- .submit(@master_ref)[0]['blog-post.body'].as_text.should == "The end of a chapter the beginning of a new one Jean-Michel Pastranova, the founder of Les Bonnes Choses, and creator of the whole concept of modern fine pastry, has decided to step down as the CEO and the Director of Workshops of Les Bonnes Choses, to focus on other projects, among which his now best-selling pastry cook books, but also to take on a primary role in a culinary television show to be announced later this year. \"I believe I've taken the Les Bonnes Choses concept as far as it can go. Les Bonnes Choses is already an entity that is driven by its people, thanks to a strong internal culture, so I don't feel like they need me as much as they used to. I'm sure they are greater ways to come, to innovate in pastry, and I'm sure Les Bonnes Choses's coming innovation will be even more mind-blowing than if I had stayed longer.\" He will remain as a senior advisor to the board, and to the workshop artists, as his daughter Selena, who has been working with him for several years, will fulfill the CEO role from now on. \"My father was able not only to create a revolutionary concept, but also a company culture that puts everyone in charge of driving the company's innovation and quality. That gives us years, maybe decades of revolutionary ideas to come, and there's still a long, wonderful path to walk in the fine pastry world.\""
140
- end
121
+ describe 'Fragments' do
122
+ before do
123
+ @link_resolver = Prismic.link_resolver("master"){|doc_link| "http://localhost/#{doc_link.id}" }
124
+ end
125
+ describe 'API::Fragments::StructuredText' do
126
+ it "returns a correct as_html on a StructuredText with list, span, embed and image" do
127
+ @api.form("everything")
128
+ .query(%([[:d = at(document.id, "UkL0gMuvzYUANCpr")]]))
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"
130
+ end
131
+ it "returns a correct as_html on a StructuredText with links" do
132
+ @api.form("everything")
133
+ .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/UkL0gMuvzYUANCpa\">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/UkL0gMuvzYUANCpX\">a second shop on Paris's Champs-Élysées</a>, and <a href=\"http://localhost/UkL0gMuvzYUANCpY\">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/UkL0gMuvzYUANCpW\">New York</a> (2000) and <a href=\"http://localhost/UkL0gMuvzYUANCpZ\">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/UkL0gMuvzYUANCpe\">ganache specialists</a>&quot;, &quot;<a href=\"http://localhost/UkL0gMuvzYUANCpc\">fruit experts</a>&quot;, or &quot;<a href=\"http://localhost/UkL0gMuvzYUANCpb\">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/UkL0gMuvzYUANCpo\">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>"
135
+ end
136
+ it "returns a correct as_text on a StructuredText" do
137
+ @api.form("everything")
138
+ .query(%([[:d = at(document.id, "UkL0gMuvzYUANCps")]]))
139
+ .submit(@master_ref)[0]['blog-post.body'].as_text.should == "The end of a chapter the beginning of a new one Jean-Michel Pastranova, the founder of Les Bonnes Choses, and creator of the whole concept of modern fine pastry, has decided to step down as the CEO and the Director of Workshops of Les Bonnes Choses, to focus on other projects, among which his now best-selling pastry cook books, but also to take on a primary role in a culinary television show to be announced later this year. \"I believe I've taken the Les Bonnes Choses concept as far as it can go. Les Bonnes Choses is already an entity that is driven by its people, thanks to a strong internal culture, so I don't feel like they need me as much as they used to. I'm sure they are greater ways to come, to innovate in pastry, and I'm sure Les Bonnes Choses's coming innovation will be even more mind-blowing than if I had stayed longer.\" He will remain as a senior advisor to the board, and to the workshop artists, as his daughter Selena, who has been working with him for several years, will fulfill the CEO role from now on. \"My father was able not only to create a revolutionary concept, but also a company culture that puts everyone in charge of driving the company's innovation and quality. That gives us years, maybe decades of revolutionary ideas to come, and there's still a long, wonderful path to walk in the fine pastry world.\""
140
+ end
141
141
 
142
- it "returns a correct as_text on a StructuredText with a separator" do
143
- @api.form("everything")
144
- .query(%([[:d = at(document.id, "UkL0gMuvzYUANCps")]]))
145
- .submit(@master_ref)[0]['blog-post.body'].as_text(' #### ').should == "The end of a chapter the beginning of a new one #### Jean-Michel Pastranova, the founder of Les Bonnes Choses, and creator of the whole concept of modern fine pastry, has decided to step down as the CEO and the Director of Workshops of Les Bonnes Choses, to focus on other projects, among which his now best-selling pastry cook books, but also to take on a primary role in a culinary television show to be announced later this year. #### \"I believe I've taken the Les Bonnes Choses concept as far as it can go. Les Bonnes Choses is already an entity that is driven by its people, thanks to a strong internal culture, so I don't feel like they need me as much as they used to. I'm sure they are greater ways to come, to innovate in pastry, and I'm sure Les Bonnes Choses's coming innovation will be even more mind-blowing than if I had stayed longer.\" #### He will remain as a senior advisor to the board, and to the workshop artists, as his daughter Selena, who has been working with him for several years, will fulfill the CEO role from now on. #### \"My father was able not only to create a revolutionary concept, but also a company culture that puts everyone in charge of driving the company's innovation and quality. That gives us years, maybe decades of revolutionary ideas to come, and there's still a long, wonderful path to walk in the fine pastry world.\""
146
- end
147
- end
148
- end
142
+ it "returns a correct as_text on a StructuredText with a separator" do
143
+ @api.form("everything")
144
+ .query(%([[:d = at(document.id, "UkL0gMuvzYUANCps")]]))
145
+ .submit(@master_ref)[0]['blog-post.body'].as_text(' #### ').should == "The end of a chapter the beginning of a new one #### Jean-Michel Pastranova, the founder of Les Bonnes Choses, and creator of the whole concept of modern fine pastry, has decided to step down as the CEO and the Director of Workshops of Les Bonnes Choses, to focus on other projects, among which his now best-selling pastry cook books, but also to take on a primary role in a culinary television show to be announced later this year. #### \"I believe I've taken the Les Bonnes Choses concept as far as it can go. Les Bonnes Choses is already an entity that is driven by its people, thanks to a strong internal culture, so I don't feel like they need me as much as they used to. I'm sure they are greater ways to come, to innovate in pastry, and I'm sure Les Bonnes Choses's coming innovation will be even more mind-blowing than if I had stayed longer.\" #### He will remain as a senior advisor to the board, and to the workshop artists, as his daughter Selena, who has been working with him for several years, will fulfill the CEO role from now on. #### \"My father was able not only to create a revolutionary concept, but also a company culture that puts everyone in charge of driving the company's innovation and quality. That gives us years, maybe decades of revolutionary ideas to come, and there's still a long, wonderful path to walk in the fine pastry world.\""
146
+ end
147
+ end
148
+ end
149
149
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prismic.io
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc6
4
+ version: 1.0.0.rc7
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Étienne Vallette d'Osia"
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-04-11 00:00:00.000000000 Z
12
+ date: 2014-05-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -76,6 +76,7 @@ extra_rdoc_files: []
76
76
  files:
77
77
  - ".gitignore"
78
78
  - ".travis.yml"
79
+ - ".yardopts"
79
80
  - Gemfile
80
81
  - Gemfile.lock
81
82
  - README.md