contentful 0.1.3 → 0.2.0

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: 055e3549fae94399369cbf11af030345ecca06a2
4
- data.tar.gz: afcffb79eb459aa3b7fb55092c5be10594d98c63
3
+ metadata.gz: be9193f04c4996121d4fc9ca04b4dc164fa2ef81
4
+ data.tar.gz: e7fbe7fde7897b9e148920026a149cfd50466d35
5
5
  SHA512:
6
- metadata.gz: 74469eca51e340966a57bf3e7d2bd4880c3c0f988e5eba58eaef49fcecc52d7a3a3ab4ea092a6211beb353642686052c92636a7502e0ef714c15793ca4d4666d
7
- data.tar.gz: 8ccc5ef2d39f5b9e3fdab75b8fe47d9b39d2e8c734b84a6638707143f5e5782abf34e9830d7f96d817531644b0ef4bf2d70f7ed536db0f835d8e4757c5fbb6e9
6
+ metadata.gz: 1a6ac299c0adbf1504a99f164170959020845d450961418caa9ae9dccb1d8097d0cb120be135288d5a195c404daded8a05ad68480a149921646dbc25aa7b260d
7
+ data.tar.gz: 634debe7bd43a3b4c8a9803441b1f20659121a9766a76146713a7d136033698e1a1e8d1a70e77408bb33d175b3805e8c50d12606c64fdf1f291236fd7f6a5582
@@ -1,3 +1,10 @@
1
+ ### 0.2.0
2
+
3
+ * Introduce new :entry_mapping configuration to enable custom Entry classes based on ContentTypes
4
+ * Update HTTP gem dependency to 0.6
5
+ * Convert arrays in query values to strings, separated by comma
6
+
7
+
1
8
  ### 0.1.3
2
9
 
3
10
  * Better link inclusion processing, prevent "stack level to deep" errors
data/README.md CHANGED
@@ -20,7 +20,7 @@ Add to your Gemfile and bundle:
20
20
  )
21
21
 
22
22
  You can query for entries, assets, etc. very similar as described in the
23
- [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:
23
+ [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
24
 
25
25
  client.content_types
26
26
  client.entry 'nyancat'
@@ -37,7 +37,7 @@ The results are returned as Contentful::Resource objects. Multiple results will
37
37
  content_type.description # "Meow."
38
38
 
39
39
 
40
- Alternatively, the data can be accessed as Ruby `Hash` with symbolized keys:
40
+ Alternatively, the data can be accessed as Ruby `Hash` with symbolized keys (and in camelCase):
41
41
 
42
42
  content_type.properties # { name: '...', description: '...' }
43
43
 
@@ -111,6 +111,7 @@ Resources, that have been requested directly (i.e. no child resources), can be f
111
111
  entries = client.entries
112
112
  entries.reload # Fetches the array of entries again
113
113
 
114
+
114
115
  ### Field Type "Object"
115
116
 
116
117
  While for known field types, the field data is accessible using methods or the `#fields` hash with symbol keys, it behaves differently for nested data of the type "Object". The client will treat them as arbitrary hashes and will not parse the data inside, which also means, this data is indexed by Ruby strings, not symbols.
@@ -173,21 +174,22 @@ You can register your custom class on client initialization:
173
174
 
174
175
  More information on `:resource_mapping` can be found in examples/resource_mapping.rb and more on custom classes in examples/custom_classes.rb
175
176
 
177
+ You can also register custom entry classes to be used based on the entry's content_type using the :entry_mapping configuration:
176
178
 
177
- ### Dynamic Entries
178
-
179
- In `dynamic_entries: :auto` mode, all entries are returned as specialized entry classes. However, you can also create these specialized classes by yourself, based on a content type:
179
+ class Cat < Contentful::Entry
180
+ # define methods based on :fields, etc
181
+ end
180
182
 
181
183
  client = Contentful::Client.new(
182
184
  space: 'cfexampleapi',
183
185
  access_token: 'b4c0n73n7fu1',
184
- dynamice_entries: :manual, # default
186
+ entry_mapping: {
187
+ 'cat' => Cat
188
+ }
185
189
  )
186
- content_type = client.content_type 'cat'
187
- MyCat = Contentful::DynamicEntry.create(content_type)
188
- client.register_dynamic_entry 'cat', MyCat
189
190
 
190
- More information on dynamic entries are available in examples/dynamic_entries.rb
191
+ client.entry('nyancat') # is instance of Cat
192
+
191
193
 
192
194
  ## License
193
195
 
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.test_files = gem.files.grep(%r{^spec/})
18
18
  gem.require_paths = ['lib']
19
19
 
20
- gem.add_dependency 'http', '~> 0', '< 0.6'
20
+ gem.add_dependency 'http', '~> 0.6'
21
21
  gem.add_dependency 'multi_json', '~> 1'
22
22
 
23
23
  gem.add_development_dependency 'bundler', '~> 1.5'
@@ -17,6 +17,7 @@ module Contentful
17
17
  authentication_mechanism: :header,
18
18
  resource_builder: ResourceBuilder,
19
19
  resource_mapping: {},
20
+ entry_mapping: {},
20
21
  raw_mode: false
21
22
  }
22
23
 
@@ -41,7 +42,7 @@ module Contentful
41
42
 
42
43
  # Returns the default configuration
43
44
  def default_configuration
44
- DEFAULT_CONFIGURATION
45
+ DEFAULT_CONFIGURATION.dup
45
46
  end
46
47
 
47
48
  # Gets the client's space
@@ -130,7 +131,12 @@ module Contentful
130
131
 
131
132
  return response if !build_resource || configuration[:raw_mode]
132
133
 
133
- result = configuration[:resource_builder].new(self, response, configuration[:resource_mapping]).run
134
+ result = configuration[:resource_builder].new(
135
+ self,
136
+ response, configuration[:resource_mapping],
137
+ configuration[:entry_mapping]
138
+ ).run
139
+
134
140
  raise result if result.is_a?(Error) && configuration[:raise_errors]
135
141
  result
136
142
  end
@@ -8,7 +8,9 @@ module Contentful
8
8
  def initialize(client, endpoint, query = {}, id = nil)
9
9
  @client = client
10
10
  @endpoint = endpoint
11
- @query = !query || query.empty? ? nil : Support.symbolize_keys(query)
11
+ @query = if query && !query.empty?
12
+ normalize_query(query)
13
+ end
12
14
 
13
15
  if id
14
16
  @type = :single
@@ -33,5 +35,19 @@ module Contentful
33
35
  def copy
34
36
  Marshal.load(Marshal.dump(self))
35
37
  end
38
+
39
+
40
+ private
41
+
42
+ def normalize_query(query)
43
+ Hash[
44
+ query.map do |key, value|
45
+ [
46
+ key.to_sym,
47
+ value.is_a?(::Array) ? value.join(',') : value
48
+ ]
49
+ end
50
+ ]
51
+ end
36
52
  end
37
53
  end
@@ -15,21 +15,23 @@ module Contentful
15
15
  DEFAULT_RESOURCE_MAPPING = {
16
16
  'Space' => Space,
17
17
  'ContentType' => ContentType,
18
- 'Entry' => :try_dynamic_entry,
18
+ 'Entry' => :find_entry_class,
19
19
  'Asset' => Asset,
20
20
  'Array' => Array,
21
21
  'Link' => Link,
22
22
  }
23
+ DEFAULT_ENTRY_MAPPING = {}
23
24
 
24
- attr_reader :client, :response, :resource_mapping, :resource
25
+ attr_reader :client, :response, :resource_mapping, :entry_mapping, :resource
25
26
 
26
27
 
27
- def initialize(client, response, resource_mapping = {})
28
+ def initialize(client, response, resource_mapping = {}, entry_mapping = {})
28
29
  @response = response
29
30
  @client = client
30
31
  @included_resources = {}
31
32
  @known_resources = Hash.new{ |h,k| h[k] = {} }
32
33
  @resource_mapping = default_resource_mapping.merge(resource_mapping)
34
+ @entry_mapping = default_entry_mapping.merge(entry_mapping)
33
35
  end
34
36
 
35
37
  # Starts the parsing process.
@@ -37,7 +39,7 @@ module Contentful
37
39
  def run
38
40
  case response.status
39
41
  when :contentful_error
40
- Error[response.raw.response.status].new(response)
42
+ Error[response.raw.status].new(response)
41
43
  when :unparsable_json
42
44
  UnparsableJson.new(response)
43
45
  when :not_contentful
@@ -80,21 +82,30 @@ module Contentful
80
82
  res
81
83
  end
82
84
 
83
- # When using Dynamic Entry Mode: Automatically converts Entry to DynamicEntry
85
+ # Checks in a custom class for an entry was defined in entry_mapping
86
+ def find_entry_class(object)
87
+ entry_mapping[content_type_id_for_entry(object)] || try_dynamic_entry(object)
88
+ end
89
+
90
+ # Automatically converts Entry to DynamicEntry if in cache
84
91
  def try_dynamic_entry(object)
85
92
  get_dynamic_entry(object) || Entry
86
93
  end
87
94
 
88
95
  # Finds the proper DynamicEntry class for an entry
89
96
  def get_dynamic_entry(object)
90
- if id = object["sys"] &&
91
- object["sys"]["contentType"] &&
92
- object["sys"]["contentType"]["sys"] &&
93
- object["sys"]["contentType"]["sys"]["id"]
94
- client.dynamic_entry_cache[id.to_sym]
97
+ if content_id = content_type_id_for_entry(object)
98
+ client.dynamic_entry_cache[content_id.to_sym]
95
99
  end
96
100
  end
97
101
 
102
+ def content_type_id_for_entry(object)
103
+ object["sys"] &&
104
+ object["sys"]["contentType"] &&
105
+ object["sys"]["contentType"]["sys"] &&
106
+ object["sys"]["contentType"]["sys"]["id"]
107
+ end
108
+
98
109
  # Uses the resource mapping to find the proper Resource class to initialize
99
110
  # for this Response object type
100
111
  #
@@ -104,6 +115,7 @@ module Contentful
104
115
  # - Symbol: Will be called as method of the ResourceBuilder itself
105
116
  def detect_resource_class(object)
106
117
  type = object["sys"] && object["sys"]["type"]
118
+
107
119
  case res_class = resource_mapping[type]
108
120
  when Symbol
109
121
  public_send(res_class, object)
@@ -118,7 +130,12 @@ module Contentful
118
130
 
119
131
  # The default mapping for #detect_resource_class
120
132
  def default_resource_mapping
121
- DEFAULT_RESOURCE_MAPPING
133
+ DEFAULT_RESOURCE_MAPPING.dup
134
+ end
135
+
136
+ # The default entry mapping
137
+ def default_entry_mapping
138
+ DEFAULT_ENTRY_MAPPING.dup
122
139
  end
123
140
 
124
141
 
@@ -7,14 +7,6 @@ module Contentful
7
7
  snake = String(object).gsub(/(?<!^)[A-Z]/) { "_#$&" }
8
8
  snake.downcase
9
9
  end
10
-
11
- # Transforms each hash key into a symbol (like in AS)
12
- def symbolize_keys(hash)
13
- result = {}
14
- # XXX remove inline rescue
15
- hash.each_key { |key| result[(key.to_sym rescue key)] = hash[key] }
16
- result
17
- end
18
10
  end
19
11
  end
20
12
  end
@@ -1,3 +1,3 @@
1
1
  module Contentful
2
- VERSION = '0.1.3'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -194,4 +194,23 @@ describe 'Client Configuration Options' do
194
194
  expect( nyancat.https_image_url ).to start_with 'https'
195
195
  end
196
196
  end
197
+
198
+ describe ':entry_mapping' do
199
+ it 'lets you register your own entry classes for certain entry types' do
200
+ class Cat < Contentful::Entry
201
+ # define methods based on :fields, etc
202
+ end
203
+
204
+ client = create_client(
205
+ entry_mapping: {
206
+ 'cat' => Cat
207
+ }
208
+ )
209
+
210
+ nyancat = vcr('entry'){ client.entry 'nyancat' }
211
+ finn = vcr('human'){ client.entry 'finn' }
212
+ expect( nyancat ).to be_a Cat
213
+ expect( finn ).to be_a Contentful::Entry
214
+ end
215
+ end
197
216
  end
@@ -0,0 +1,95 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://cdn.contentful.com/spaces/cfexampleapi/entries/finn
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - RubyContentfulGem/0.1.3
12
+ Authorization:
13
+ - Bearer b4c0n73n7fu1
14
+ Content-Type:
15
+ - application/vnd.contentful.delivery.v1+json
16
+ Host:
17
+ - cdn.contentful.com
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Date:
24
+ - Fri, 18 Apr 2014 17:56:56 GMT
25
+ Server:
26
+ - nginx/1.1.19
27
+ Access-Control-Allow-Headers:
28
+ - Accept,Accept-Language,Authorization,Cache-Control,Content-Length,Content-Range,Content-Type,DNT,Destination,Expires,If-Match,If-Modified-Since,If-None-Match,Keep-Alive,Last-Modified,Origin,Pragma,Range,User-Agent,X-Http-Method-Override,X-Mx-ReqToken,X-Requested-With,X-Contentful-Version,X-Contentful-Content-Type,X-Contentful-Organization
29
+ Access-Control-Allow-Methods:
30
+ - GET,HEAD,OPTIONS
31
+ Access-Control-Allow-Origin:
32
+ - "*"
33
+ Access-Control-Max-Age:
34
+ - '86400'
35
+ Cache-Control:
36
+ - max-age=0
37
+ Content-Type:
38
+ - application/vnd.contentful.delivery.v1+json
39
+ Etag:
40
+ - "\"fcdc41e711c72e3cbc389211fde21287\""
41
+ X-Contentful-Request-Id:
42
+ - f1c-737727925
43
+ Content-Length:
44
+ - '591'
45
+ Accept-Ranges:
46
+ - bytes
47
+ Via:
48
+ - 1.1 varnish
49
+ Age:
50
+ - '0'
51
+ X-Served-By:
52
+ - cache-fra1229-FRA
53
+ X-Cache:
54
+ - MISS
55
+ X-Cache-Hits:
56
+ - '0'
57
+ Vary:
58
+ - Accept-Encoding
59
+ body:
60
+ encoding: UTF-8
61
+ string: |
62
+ {
63
+ "fields": {
64
+ "name": "Finn",
65
+ "description": "Fearless adventurer! Defender of pancakes.",
66
+ "likes": [
67
+ "adventure"
68
+ ]
69
+ },
70
+ "sys": {
71
+ "space": {
72
+ "sys": {
73
+ "type": "Link",
74
+ "linkType": "Space",
75
+ "id": "cfexampleapi"
76
+ }
77
+ },
78
+ "type": "Entry",
79
+ "contentType": {
80
+ "sys": {
81
+ "type": "Link",
82
+ "linkType": "ContentType",
83
+ "id": "human"
84
+ }
85
+ },
86
+ "id": "finn",
87
+ "revision": 6,
88
+ "createdAt": "2013-06-27T22:46:21.450Z",
89
+ "updatedAt": "2013-09-09T16:15:01.297Z",
90
+ "locale": "en-US"
91
+ }
92
+ }
93
+ http_version:
94
+ recorded_at: Fri, 18 Apr 2014 17:56:56 GMT
95
+ recorded_with: VCR 2.9.0
@@ -11,6 +11,14 @@ describe Contentful::Request do
11
11
  end
12
12
  end
13
13
 
14
+ describe '#query' do
15
+ it 'converts arrays given in query to comma strings' do
16
+ client = create_client
17
+ request = Contentful::Request.new(client, '/entries', {'fields.likes[in]' => ['jake', 'finn']})
18
+ expect( request.query[:'fields.likes[in]'] ).to eq 'jake,finn'
19
+ end
20
+ end
21
+
14
22
  context '[single resource]' do
15
23
  let(:request){
16
24
  Contentful::Request.new(create_client, '/content_types', nil, 'nyancat')
metadata CHANGED
@@ -1,23 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contentful
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Contentful GmbH (Jan Lelis)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-16 00:00:00.000000000 Z
11
+ date: 2014-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- - - "<"
21
18
  - !ruby/object:Gem::Version
22
19
  version: '0.6'
23
20
  type: :runtime
@@ -25,9 +22,6 @@ dependencies:
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - "~>"
28
- - !ruby/object:Gem::Version
29
- version: '0'
30
- - - "<"
31
25
  - !ruby/object:Gem::Version
32
26
  version: '0.6'
33
27
  - !ruby/object:Gem::Dependency
@@ -225,6 +219,7 @@ files:
225
219
  - spec/fixtures/vcr_cassettes/entry.yml
226
220
  - spec/fixtures/vcr_cassettes/entry_cache.yml
227
221
  - spec/fixtures/vcr_cassettes/field.yml
222
+ - spec/fixtures/vcr_cassettes/human.yml
228
223
  - spec/fixtures/vcr_cassettes/locale.yml
229
224
  - spec/fixtures/vcr_cassettes/location.yml
230
225
  - spec/fixtures/vcr_cassettes/not_found.yml
@@ -299,6 +294,7 @@ test_files:
299
294
  - spec/fixtures/vcr_cassettes/entry.yml
300
295
  - spec/fixtures/vcr_cassettes/entry_cache.yml
301
296
  - spec/fixtures/vcr_cassettes/field.yml
297
+ - spec/fixtures/vcr_cassettes/human.yml
302
298
  - spec/fixtures/vcr_cassettes/locale.yml
303
299
  - spec/fixtures/vcr_cassettes/location.yml
304
300
  - spec/fixtures/vcr_cassettes/not_found.yml