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