contentful 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +1 -0
- data/CHANGELOG.md +5 -0
- data/README.md +122 -91
- data/lib/contentful/client.rb +0 -2
- data/lib/contentful/resource.rb +10 -8
- data/lib/contentful/response.rb +9 -3
- data/lib/contentful/version.rb +1 -1
- data/problem.rb +39 -0
- data/spec/response_spec.rb +7 -0
- metadata +5 -4
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -9,65 +9,78 @@ Ruby client for the [Contentful](https://www.contentful.com) Content Delivery AP
|
|
9
9
|
|
10
10
|
Add to your Gemfile and bundle:
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
```bash
|
13
|
+
gem 'contentful'
|
14
|
+
```
|
14
15
|
|
15
16
|
## Usage
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
```ruby
|
19
|
+
client = Contentful::Client.new(
|
20
|
+
access_token: 'b4c0n73n7fu1',
|
21
|
+
space: 'cfexampleapi'
|
22
|
+
)
|
23
|
+
```
|
21
24
|
|
22
25
|
You can query for entries, assets, etc. very similar as described in the
|
23
26
|
[Delivery API Documentation](https://www.contentful.com/developers/documentation/content-delivery-api/). Please note, that **all methods of the Ruby client library are snake_cased, instead of JavaScript's camelCase**:
|
24
27
|
|
25
|
-
|
26
|
-
|
28
|
+
```ruby
|
29
|
+
client.content_types
|
30
|
+
client.entry 'nyancat'
|
31
|
+
```
|
27
32
|
|
28
33
|
You can pass the usual filter options to the query:
|
29
34
|
|
30
|
-
|
31
|
-
|
32
|
-
|
35
|
+
```ruby
|
36
|
+
client.entries('sys.id[ne]' => 'nyancat') # query for all entries except 'nyancat'
|
37
|
+
client.entries(include: 1) # include one level of linked resources
|
38
|
+
```
|
33
39
|
|
34
40
|
The results are returned as Contentful::Resource objects. Multiple results will be returned as Contentful::Array. The properties of a resource can be accessed through Ruby methods.
|
35
41
|
|
36
|
-
|
37
|
-
|
38
|
-
|
42
|
+
```ruby
|
43
|
+
content_type = client.content_type 'cat'
|
44
|
+
content_type.description # "Meow."
|
45
|
+
```
|
39
46
|
|
40
47
|
Alternatively, the data can be accessed as Ruby `Hash` with symbolized keys (and in camelCase):
|
41
48
|
|
42
|
-
|
43
|
-
|
49
|
+
```ruby
|
50
|
+
content_type.properties # { name: '...', description: '...' }
|
51
|
+
```
|
44
52
|
|
45
53
|
System Properties behave the same and can be accessed via the `#sys` method.
|
46
54
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
55
|
+
```ruby
|
56
|
+
content_type.id # => 'cat'
|
57
|
+
entry.type # => 'Entry'
|
58
|
+
asset.sys # { id: '...', type: '...' }
|
59
|
+
```
|
51
60
|
|
52
61
|
Entry Fields usually don't have direct method accessors, since they are based on individual content types. These fields can be accessed through the `#fields` method:
|
53
62
|
|
54
|
-
|
55
|
-
|
63
|
+
```ruby
|
64
|
+
entry = client.entry 'nyancat'
|
65
|
+
entry.fields[:color] # rainbow
|
66
|
+
```
|
56
67
|
|
57
68
|
Please note, that no field type conversions will be done for entries by default.
|
58
69
|
|
59
|
-
|
60
70
|
### Dynamic Entries
|
61
71
|
|
62
72
|
However, you can (and should) set `:dynamic_entries` to `:auto` in your client configuration. When using this option, the client will fetch all available content types and use them to create dynamic entries on the fly.
|
63
73
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
74
|
+
```ruby
|
75
|
+
client = Contentful::Client.new(
|
76
|
+
access_token: 'b4c0n73n7fu1',
|
77
|
+
space: 'cfexampleapi',
|
78
|
+
dynamic_entries: :auto,
|
79
|
+
)
|
80
|
+
|
81
|
+
entry = client.entry 'nyancat' # => #<Contentful::DynamicEntry[cat]: ...>
|
82
|
+
entry.color # => 'rainbow'
|
83
|
+
```
|
71
84
|
|
72
85
|
Dynamic entries will have getter classes for the fields and do type conversions properly.
|
73
86
|
|
@@ -85,32 +98,35 @@ Arrays also have a `#next_page` URL, which will rerun the request with a increas
|
|
85
98
|
|
86
99
|
You can easily request a resource that is represented by a link by calling `#resolve`:
|
87
100
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
101
|
+
```ruby
|
102
|
+
happycat = client.entry 'happycat'
|
103
|
+
happycat.fields[:image]
|
104
|
+
# => #<Contentful::Link: @sys={:type=>"Link", :linkType=>"Asset", :id=>"happycat"}>
|
105
|
+
happycat.fields[:image].resolve # => #<Contentful::Asset: @fields={ ...
|
106
|
+
```
|
93
107
|
|
94
108
|
### Assets
|
95
109
|
|
96
110
|
There is a helpful method to add image resize options for an asset image:
|
97
111
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
client.asset('happycat').image_url width: 300, height: 200, format: 'jpg', quality: 100
|
103
|
-
# => "//images.contentful.com/cfexampleapi/3MZPnjZTIskAIIkuuosCss/
|
104
|
-
# 382a48dfa2cb16c47aa2c72f7b23bf09/happycatw.jpg?w=300&h=200&fm=jpg&q=100"
|
112
|
+
```ruby
|
113
|
+
client.asset('happycat').image_url
|
114
|
+
# => "//images.contentful.com/cfexampleapi/3MZPnjZTIskAIIkuuosCss/
|
115
|
+
# 382a48dfa2cb16c47aa2c72f7b23bf09/happycatw.jpg"
|
105
116
|
|
117
|
+
client.asset('happycat').image_url width: 300, height: 200, format: 'jpg', quality: 100
|
118
|
+
# => "//images.contentful.com/cfexampleapi/3MZPnjZTIskAIIkuuosCss/
|
119
|
+
# 382a48dfa2cb16c47aa2c72f7b23bf09/happycatw.jpg?w=300&h=200&fm=jpg&q=100"
|
120
|
+
```
|
106
121
|
|
107
122
|
### Resource Options
|
108
123
|
|
109
124
|
Resources, that have been requested directly (i.e. no child resources), can be fetched from the server again by calling `#reload`:
|
110
125
|
|
111
|
-
|
112
|
-
|
113
|
-
|
126
|
+
```ruby
|
127
|
+
entries = client.entries
|
128
|
+
entries.reload # Fetches the array of entries again
|
129
|
+
```
|
114
130
|
|
115
131
|
### Field Type "Object"
|
116
132
|
|
@@ -156,80 +172,95 @@ See next paragraph for explanation
|
|
156
172
|
|
157
173
|
You can define your own classes that will be returned instead of the predefined ones. Consider, you want to build a better Asset class. One way to do this is:
|
158
174
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
175
|
+
```ruby
|
176
|
+
class MyBetterAsset < Contentful::Asset
|
177
|
+
def https_image_url
|
178
|
+
image_url.sub %r<\A//>, 'https://'
|
179
|
+
end
|
180
|
+
end
|
181
|
+
```
|
164
182
|
|
165
183
|
You can register your custom class on client initialization:
|
166
184
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
185
|
+
```ruby
|
186
|
+
client = Contentful::Client.new(
|
187
|
+
space: 'cfexampleapi',
|
188
|
+
access_token: 'b4c0n73n7fu1',
|
189
|
+
resource_mapping: {
|
190
|
+
'Asset' => MyBetterAsset
|
191
|
+
}
|
192
|
+
)
|
193
|
+
```
|
174
194
|
|
175
195
|
More information on `:resource_mapping` can be found in examples/resource_mapping.rb and more on custom classes in examples/custom_classes.rb
|
176
196
|
|
177
197
|
You can also register custom entry classes to be used based on the entry's content_type using the :entry_mapping configuration:
|
178
198
|
|
179
|
-
|
180
|
-
|
181
|
-
|
199
|
+
```ruby
|
200
|
+
class Cat < Contentful::Entry
|
201
|
+
# define methods based on :fields, etc
|
202
|
+
end
|
182
203
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
client.entry('nyancat') # is instance of Cat
|
204
|
+
client = Contentful::Client.new(
|
205
|
+
space: 'cfexampleapi',
|
206
|
+
access_token: 'b4c0n73n7fu1',
|
207
|
+
entry_mapping: {
|
208
|
+
'cat' => Cat
|
209
|
+
}
|
210
|
+
)
|
192
211
|
|
212
|
+
client.entry('nyancat') # is instance of Cat
|
213
|
+
```
|
193
214
|
|
194
215
|
## Synchronization
|
195
216
|
|
196
217
|
The client also includes a wrapper for the synchronization endpoint. You can initialize it with the options described in the [Delivery API Documentation](https://www.contentful.com/developers/documentation/content-delivery-api/#sync) or an URL you received from a previous sync:
|
197
218
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
219
|
+
```ruby
|
220
|
+
client = Contentful::Client.new(
|
221
|
+
access_token: 'b4c0n73n7fu1',
|
222
|
+
space: 'cfexampleapi',
|
223
|
+
default_locale: 'en-US'
|
224
|
+
)
|
225
|
+
|
226
|
+
sync = client.sync(initial: true, type: 'Deletion') # Only returns deleted entries and assets
|
227
|
+
sync = client.sync("https://cdn.contentful.com/spaces/cfexampleapi/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4gr...sGPg") # Continues a sync
|
228
|
+
```
|
205
229
|
|
206
230
|
You can access the results either wrapped in `Contentful::SyncPage` objects:
|
207
231
|
|
208
|
-
|
209
|
-
|
210
|
-
|
232
|
+
```ruby
|
233
|
+
sync.each_page do |page|
|
234
|
+
# Find resources at: page.items
|
235
|
+
end
|
211
236
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
237
|
+
# More explicit version:
|
238
|
+
page = sync.first_page
|
239
|
+
until sync.completed?
|
240
|
+
page = sync.next_page
|
241
|
+
end
|
242
|
+
```
|
217
243
|
|
218
244
|
Or directly iterative over all resources:
|
219
245
|
|
220
|
-
|
221
|
-
|
222
|
-
|
246
|
+
```ruby
|
247
|
+
sync.each_item do |resource|
|
248
|
+
# ...
|
249
|
+
end
|
250
|
+
```
|
223
251
|
|
224
252
|
When a sync is completed, the next sync url can be read from the Sync or SyncPage object:
|
225
253
|
|
226
|
-
|
254
|
+
```ruby
|
255
|
+
sync.next_sync_url
|
256
|
+
```
|
227
257
|
|
228
258
|
**Please note** that synchronization entries come in all locales, so make sure, you supply a :default_locale property to the client configuration, when using the sync feature. This locale will be returned by default, when you call `Entry#fields`. The other localized data will also be saved and can be accessed by calling the fields method with a locale parameter:
|
229
259
|
|
230
|
-
|
231
|
-
|
232
|
-
|
260
|
+
```ruby
|
261
|
+
first_entry = client.sync(initial: true, type: 'Entry').first_page.items.first
|
262
|
+
first_entry.fields('de-DE') # Returns German localizations
|
263
|
+
```
|
233
264
|
|
234
265
|
## License
|
235
266
|
|
data/lib/contentful/client.rb
CHANGED
@@ -4,8 +4,6 @@ require_relative 'resource_builder'
|
|
4
4
|
require_relative 'sync'
|
5
5
|
|
6
6
|
require 'http'
|
7
|
-
# see: https://github.com/tarcieri/http/commit/6a2a9d22902572d672dfc7c7b250d022364c8e01#commitcomment-6192269
|
8
|
-
require 'cgi'
|
9
7
|
|
10
8
|
module Contentful
|
11
9
|
# The client object is initialized with a space and a key and then used
|
data/lib/contentful/resource.rb
CHANGED
@@ -8,8 +8,8 @@ module Contentful
|
|
8
8
|
# You can define your own classes that behave like contentful resources:
|
9
9
|
# See examples/custom_classes.rb to see how.
|
10
10
|
#
|
11
|
-
# Take a look at examples/resource_mapping.rb on how to register them
|
12
|
-
# by the client by default
|
11
|
+
# Take a look at examples/resource_mapping.rb on how to register them
|
12
|
+
# to be returned by the client by default
|
13
13
|
module Resource
|
14
14
|
COERCIONS = {
|
15
15
|
string: ->(v) { v.to_s },
|
@@ -26,7 +26,8 @@ module Contentful
|
|
26
26
|
@nested_locale_fields = nested_locale_fields
|
27
27
|
@default_locale = default_locale
|
28
28
|
|
29
|
-
@properties = extract_from_object
|
29
|
+
@properties = extract_from_object(object, :property,
|
30
|
+
self.class.property_coercions.keys)
|
30
31
|
@request = request
|
31
32
|
@client = client
|
32
33
|
end
|
@@ -72,10 +73,9 @@ module Contentful
|
|
72
73
|
if object
|
73
74
|
keys ||= object.keys
|
74
75
|
keys.each.with_object({}) do |name, res|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
)
|
76
|
+
value = object.is_a?(::Array) ? object : object[name.to_s]
|
77
|
+
kind = self.class.public_send(:"#{namespace}_coercions")[name.to_sym]
|
78
|
+
res[name.to_sym] = coerce_value_or_array(value, kind)
|
79
79
|
end
|
80
80
|
else
|
81
81
|
{}
|
@@ -83,7 +83,9 @@ module Contentful
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def coerce_value_or_array(value, what = nil)
|
86
|
-
if value.
|
86
|
+
if value.nil?
|
87
|
+
nil
|
88
|
+
elsif value.is_a? ::Array
|
87
89
|
value.map { |v| coerce_or_create_class(v, what) }
|
88
90
|
else
|
89
91
|
coerce_or_create_class(value, what)
|
data/lib/contentful/response.rb
CHANGED
@@ -27,14 +27,20 @@ module Contentful
|
|
27
27
|
@request = request
|
28
28
|
@status = :ok
|
29
29
|
|
30
|
-
if
|
30
|
+
if no_content_response?
|
31
|
+
@status = :no_content
|
32
|
+
@object = true
|
33
|
+
elsif parse_json!
|
31
34
|
parse_contentful_error!
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
35
|
-
|
36
38
|
private
|
37
39
|
|
40
|
+
def no_content_response?
|
41
|
+
@raw.to_s == '' && @raw.status == 204
|
42
|
+
end
|
43
|
+
|
38
44
|
def parse_json!
|
39
45
|
@object = MultiJson.load(raw.to_s)
|
40
46
|
true
|
@@ -61,4 +67,4 @@ module Contentful
|
|
61
67
|
end
|
62
68
|
|
63
69
|
end
|
64
|
-
end
|
70
|
+
end
|
data/lib/contentful/version.rb
CHANGED
data/problem.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'pry'
|
2
|
+
module PlayboyContentful
|
3
|
+
class ContentType < Contentful::ContentType
|
4
|
+
|
5
|
+
def type_for_field_with_name(name)
|
6
|
+
fields.each do |field|
|
7
|
+
return field.type if field.id == name
|
8
|
+
end
|
9
|
+
return nil
|
10
|
+
end
|
11
|
+
|
12
|
+
# Depending on if the field supports full text search, the call needs may
|
13
|
+
# or may not need to append [eq] to the "fields.<field_name>" filter
|
14
|
+
def equality_string_for_field_with_name(name)
|
15
|
+
field_type = type_for_field_with_name(name)
|
16
|
+
raise "Could not build equality string for #{name} because field was not found." if field_type == nil
|
17
|
+
return "fields.#{name}" if field_type == "Symbol"
|
18
|
+
return "fields.#{name}[match]" if field_type == "Text"
|
19
|
+
"fields.#{name}[eq]"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
CONTENTFUL_ACCESS_TOKEN="9b3b92d9929dc96744809e3b290bd1c6e6d9f10f7e4e7217ed50524fc0d9728d"
|
26
|
+
CONTENTFUL_SPACE="t8g5epyvf6nt"
|
27
|
+
|
28
|
+
client = Contentful::Client.new(
|
29
|
+
access_token: CONTENTFUL_ACCESS_TOKEN,
|
30
|
+
space: CONTENTFUL_SPACE,
|
31
|
+
dynamic_entries: :auto,
|
32
|
+
resource_mapping: {
|
33
|
+
'ContentType' => PlayboyContentful::ContentType
|
34
|
+
}
|
35
|
+
)
|
36
|
+
|
37
|
+
client.entry('2ks0eTNWoMw0026sUgsMWW')
|
38
|
+
|
39
|
+
client.entries({"content_type"=>"3VZz9HnPy02usuACK08WUw", :limit=>1000})
|
data/spec/response_spec.rb
CHANGED
@@ -35,6 +35,13 @@ describe Contentful::Response do
|
|
35
35
|
it 'returns :unparsable_json for unparsable json responses' do
|
36
36
|
expect( unparsable_response.status ).to eq :unparsable_json
|
37
37
|
end
|
38
|
+
|
39
|
+
it 'returns :no_content for responses without content' do
|
40
|
+
raw_response = ''
|
41
|
+
mock(raw_response).status {204}
|
42
|
+
no_content_response = Contentful::Response.new raw_response
|
43
|
+
expect( no_content_response.status).to eq :no_content
|
44
|
+
end
|
38
45
|
end
|
39
46
|
|
40
47
|
describe "#error_message" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: contentful
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-07-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: http
|
@@ -211,6 +211,7 @@ files:
|
|
211
211
|
- lib/contentful/version.rb
|
212
212
|
- lib/contentful.rb
|
213
213
|
- LICENSE.txt
|
214
|
+
- problem.rb
|
214
215
|
- Rakefile
|
215
216
|
- README.md
|
216
217
|
- spec/array_spec.rb
|
@@ -288,7 +289,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
288
289
|
version: '0'
|
289
290
|
segments:
|
290
291
|
- 0
|
291
|
-
hash: -
|
292
|
+
hash: -2280169027525600462
|
292
293
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
293
294
|
none: false
|
294
295
|
requirements:
|
@@ -297,7 +298,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
297
298
|
version: '0'
|
298
299
|
segments:
|
299
300
|
- 0
|
300
|
-
hash: -
|
301
|
+
hash: -2280169027525600462
|
301
302
|
requirements: []
|
302
303
|
rubyforge_project:
|
303
304
|
rubygems_version: 1.8.23.2
|