contentful_lite 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +257 -0
- data/lib/contentful_lite/asset.rb +30 -0
- data/lib/contentful_lite/assets_array.rb +12 -0
- data/lib/contentful_lite/base_array.rb +29 -0
- data/lib/contentful_lite/client.rb +110 -0
- data/lib/contentful_lite/common_data.rb +95 -0
- data/lib/contentful_lite/deleted_entry.rb +10 -0
- data/lib/contentful_lite/entries_array.rb +62 -0
- data/lib/contentful_lite/entry.rb +52 -0
- data/lib/contentful_lite/entry_mapping.rb +23 -0
- data/lib/contentful_lite/link.rb +40 -0
- data/lib/contentful_lite/validations/entry.rb +68 -0
- data/lib/contentful_lite/validations/included_asset_validator.rb +14 -0
- data/lib/contentful_lite/validations/included_child_validator.rb +40 -0
- data/lib/contentful_lite/validations/included_entry_validator.rb +24 -0
- data/lib/contentful_lite/version.rb +3 -0
- data/lib/contentful_lite.rb +12 -0
- data/spec/asset_spec.rb +61 -0
- data/spec/assets_array_spec.rb +32 -0
- data/spec/base_array_spec.rb +25 -0
- data/spec/client_spec.rb +129 -0
- data/spec/common_data_spec.rb +111 -0
- data/spec/deleted_entry_spec.rb +30 -0
- data/spec/entries_array_spec.rb +102 -0
- data/spec/entry_mapping_spec.rb +20 -0
- data/spec/entry_spec.rb +84 -0
- data/spec/link_spec.rb +66 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/validations_spec.rb +366 -0
- metadata +186 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
module ContentfulLite
|
2
|
+
class Entry
|
3
|
+
include CommonData
|
4
|
+
include EntryMapping
|
5
|
+
include Validations::Entry
|
6
|
+
|
7
|
+
# The id for the content type of this entry
|
8
|
+
attr_reader :content_type_id
|
9
|
+
|
10
|
+
# @param raw [Hash] raw response from Contentful API
|
11
|
+
# @api private
|
12
|
+
def initialize(raw)
|
13
|
+
super(raw)
|
14
|
+
@content_type_id = raw['sys']['contentType']['sys']['id']
|
15
|
+
@localized_fields.values.each do |fields|
|
16
|
+
fields.transform_values! { |value| build_link(value) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Gets the URL to view/edit the entry on Contentful webapp
|
21
|
+
# @return [String]
|
22
|
+
def contentful_link
|
23
|
+
"https://app.contentful.com/spaces/#{space_id}/entries/#{id}"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Defines a field existing on the content type. This macro registers the
|
27
|
+
# accessor for that field
|
28
|
+
# @param attrs [Array<Symbol,String>] The field names
|
29
|
+
# @param default [Object, nil] The default value to return if field is not present on API response
|
30
|
+
# @param localizable [Boolean] If the field is marked as localizable
|
31
|
+
# @example Defines two string localizable localized fields
|
32
|
+
# field_reader :first_name, :last_name, localizable: true
|
33
|
+
# @see https://github.com/JuulLabs-OSS/contentful_lite#creating-your-model-classes-with-macros
|
34
|
+
def self.field_reader(*attrs, default: nil, localizable: false)
|
35
|
+
attrs.each do |k|
|
36
|
+
define_method(k) do |locale: nil|
|
37
|
+
field = fields(locale: localizable ? locale : default_locale)[k.to_s]
|
38
|
+
field.nil? ? default : field
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def build_link(value)
|
46
|
+
return value.map!{ |element| build_link(element) } if value.is_a?(Array)
|
47
|
+
return value unless value.is_a?(Hash) && value.fetch('sys', {}).fetch('type', '') == 'Link'
|
48
|
+
|
49
|
+
ContentfulLite::Link.new(value)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module ContentfulLite
|
4
|
+
# @api private
|
5
|
+
module EntryMapping
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do |base_klass|
|
9
|
+
base_klass.define_singleton_method(:content_type_id) do |name|
|
10
|
+
klass = self
|
11
|
+
base_klass.class_eval do
|
12
|
+
@mappings ||= {}
|
13
|
+
@mappings[name] = klass
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
base_klass.define_singleton_method(:get_class) do |content_type_id|
|
18
|
+
@mappings ||= {}
|
19
|
+
@mappings[content_type_id] || base_klass
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ContentfulLite
|
2
|
+
# A link to any type of contentful entity
|
3
|
+
class Link
|
4
|
+
# The unique id of the linked entity
|
5
|
+
attr_reader :id
|
6
|
+
# The type of the linked entity
|
7
|
+
attr_reader :type
|
8
|
+
|
9
|
+
# @param input [ContentfulLite::CommonData, Hash] data to build the instance
|
10
|
+
# @api private
|
11
|
+
def initialize(input)
|
12
|
+
if input.is_a?(ContentfulLite::CommonData)
|
13
|
+
@id = input.id
|
14
|
+
@type = input.sys['type'].downcase.to_sym
|
15
|
+
else
|
16
|
+
@type = input['sys']['linkType'].downcase.to_sym
|
17
|
+
@id = input['sys']['id']
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Equality comparison
|
22
|
+
# @param other [Object] the object to compare
|
23
|
+
# @return [Boolean] true if other is ContentfulLite::Link with same id and type
|
24
|
+
def ==(other)
|
25
|
+
self.class == other.class && type == other.type && id == other.id
|
26
|
+
end
|
27
|
+
|
28
|
+
# Provided for compatibility with Rails JSON serializer
|
29
|
+
# @return [Hash] a Hash representation of the link, to be formated as JSON
|
30
|
+
def as_json(**)
|
31
|
+
{
|
32
|
+
'sys' => {
|
33
|
+
'type' => "Link",
|
34
|
+
'linkType' => type.to_s.capitalize,
|
35
|
+
'id' => id
|
36
|
+
}
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_model'
|
3
|
+
require 'contentful_lite/validations/included_child_validator'
|
4
|
+
require 'contentful_lite/validations/included_asset_validator'
|
5
|
+
require 'contentful_lite/validations/included_entry_validator'
|
6
|
+
|
7
|
+
module ContentfulLite
|
8
|
+
module Validations
|
9
|
+
module Entry
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
|
12
|
+
included do |base_class|
|
13
|
+
base_class.include(ActiveModel::Validations)
|
14
|
+
base_class.define_method(:errors) do |locale: nil|
|
15
|
+
@errors ||= Hash.new { |hash, key| hash[key] = ActiveModel::Errors.new(self) }
|
16
|
+
@errors[locale || self.locale]
|
17
|
+
end
|
18
|
+
base_class.define_method(:valid?) do |locale: nil|
|
19
|
+
with_locale(locale) { super() }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @!method self.validates_included_entry(*attr_names, **options)
|
24
|
+
# Adds a validation on one or more fields to ensure it's a reference field
|
25
|
+
# and the values are entries with one of the specified types
|
26
|
+
# @param attr_names [Array<string>] the fields to validate
|
27
|
+
# @param options [Hash] the options Hash
|
28
|
+
# @option options [Array<Class>] :allowed_models the contentful content types that will be allowed
|
29
|
+
# @option options [Boolean] :allow_blank if true it allows the field to be empty
|
30
|
+
# @option options [Boolean] :array if true, the field must be an array of references.
|
31
|
+
# If not, it must be a single reference.
|
32
|
+
class_methods do
|
33
|
+
def validates_included_entry(*attr_names)
|
34
|
+
validates_with IncludedEntryValidator, _merge_attributes(attr_names)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# @!method self.validates_included_asset(*attr_names, **options)
|
39
|
+
# Adds a validation on one or more fields to ensure it's a reference field
|
40
|
+
# and the values are assets
|
41
|
+
# @param attr_names [Array<string>] the fields to validate
|
42
|
+
# @param options [Hash] the options Hash
|
43
|
+
# @option options [Array<Class>] :type the asset content types that will be allowed
|
44
|
+
# @option options [Boolean] :allow_blank if true it allows the field to be empty
|
45
|
+
# @option options [Boolean] :array if true, the field must be an array of references.
|
46
|
+
# If not, it must be a single reference.
|
47
|
+
class_methods do
|
48
|
+
def validates_included_asset(*attr_names)
|
49
|
+
validates_with IncludedAssetValidator, _merge_attributes(attr_names)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Validates all locales
|
54
|
+
# @return [boolean] is entry valid across al locales?
|
55
|
+
def valid_for_all_locales?
|
56
|
+
locales.map do |locale|
|
57
|
+
valid?(locale: locale)
|
58
|
+
end.all?
|
59
|
+
end
|
60
|
+
|
61
|
+
# Gets the error messages for all the locales at once
|
62
|
+
# @return [Hash] a hash with locale as keys and errors as values
|
63
|
+
def errors_for_all_locales
|
64
|
+
@errors
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ContentfulLite
|
2
|
+
module Validations
|
3
|
+
# @api private
|
4
|
+
class IncludedAssetValidator < ActiveModel::EachValidator
|
5
|
+
include IncludedChildValidator
|
6
|
+
add_options_keys :type
|
7
|
+
|
8
|
+
def validate_child(record, attr_name, value, idx = nil)
|
9
|
+
record_error(record, attr_name, "value#{idx} is not a published asset") && return unless value.is_a?(ContentfulLite::Asset)
|
10
|
+
record_error(record, attr_name, "value#{idx} has an invalid asset type. Expecting #{options[:type]}") if options[:type] && !value&.content_type&.include?(options[:type].to_s)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ContentfulLite
|
2
|
+
module Validations
|
3
|
+
# @api private
|
4
|
+
module IncludedChildValidator
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
BASE_OPTIONS = %i[allow_blank array].freeze
|
7
|
+
|
8
|
+
def validate_each(record, attr_name, value)
|
9
|
+
if value.blank?
|
10
|
+
record_error(record, attr_name, "value is blank") unless options[:allow_blank]
|
11
|
+
elsif options[:array]
|
12
|
+
validate_array(record, attr_name, value)
|
13
|
+
else
|
14
|
+
validate_child(record, attr_name, value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def record_error(record, attr_name, message)
|
21
|
+
record.errors.add(attr_name, :invalid, { message: message }.merge(options.except(self.class.options_keys)))
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate_array(record, attr_name, value)
|
25
|
+
record_error(record, attr_name, "value is not an array") && return unless value.is_a?(Array)
|
26
|
+
value.each_with_index { |asset, idx| validate_child(record, attr_name, asset, "[#{idx}]") }
|
27
|
+
end
|
28
|
+
|
29
|
+
class_methods do
|
30
|
+
def add_options_keys(*options)
|
31
|
+
@options_keys = BASE_OPTIONS + options
|
32
|
+
end
|
33
|
+
|
34
|
+
def options_keys
|
35
|
+
@options_keys
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ContentfulLite
|
2
|
+
module Validations
|
3
|
+
# @api private
|
4
|
+
class IncludedEntryValidator < ActiveModel::EachValidator
|
5
|
+
include IncludedChildValidator
|
6
|
+
add_options_keys :allowed_models
|
7
|
+
|
8
|
+
def validate_child(record, attr_name, value, idx = nil)
|
9
|
+
unless value.is_a?(ContentfulLite::Entry)
|
10
|
+
record_error(record, attr_name, "value#{idx} is not a published entry")
|
11
|
+
return
|
12
|
+
end
|
13
|
+
record_error(record, attr_name, "value has invalid child entry #{value.id}") unless value.valid?(locale: record.locale)
|
14
|
+
record_error(record, attr_name, "value#{idx} has an invalid entry model. Expecting #{options[:allowed_models]}") if invalid_model?(value)
|
15
|
+
end
|
16
|
+
|
17
|
+
def invalid_model?(value)
|
18
|
+
return false unless options[:allowed_models]
|
19
|
+
|
20
|
+
options[:allowed_models]&.none?{ |type| value.is_a?(type) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "contentful_lite/validations/entry"
|
2
|
+
require "contentful_lite/version"
|
3
|
+
require "contentful_lite/common_data"
|
4
|
+
require "contentful_lite/link"
|
5
|
+
require "contentful_lite/asset"
|
6
|
+
require "contentful_lite/entry_mapping"
|
7
|
+
require "contentful_lite/entry"
|
8
|
+
require "contentful_lite/deleted_entry"
|
9
|
+
require "contentful_lite/base_array"
|
10
|
+
require "contentful_lite/assets_array"
|
11
|
+
require "contentful_lite/entries_array"
|
12
|
+
require "contentful_lite/client"
|
data/spec/asset_spec.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe ContentfulLite::Asset do
|
4
|
+
let(:asset_hash) { JSON.parse(File.read('fixtures/assets/nyancat.json')) }
|
5
|
+
let(:instance) { ContentfulLite::Asset.new(asset_hash) }
|
6
|
+
|
7
|
+
describe '#attributes' do
|
8
|
+
it { expect(instance.title).to eq 'Nyan Cat' }
|
9
|
+
it { expect(instance.description).to eq '' }
|
10
|
+
it { expect(instance.url).to eq '//images.ctfassets.net/cfexampleapi/4gp6taAwW4CmSgumq2ekUm/9da0cd1936871b8d72343e895a00d611/Nyan_cat_250px_frame.png' }
|
11
|
+
it { expect(instance.file_name).to eq 'Nyan_cat_250px_frame.png' }
|
12
|
+
it { expect(instance.content_type).to eq 'image/png' }
|
13
|
+
|
14
|
+
context 'for unpublished assets without a file' do
|
15
|
+
let(:asset_hash) { JSON.parse(File.read('fixtures/assets/unpublished.json')) }
|
16
|
+
|
17
|
+
it { expect(instance.title).to be_nil }
|
18
|
+
it { expect(instance.description).to eq '' }
|
19
|
+
it { expect(instance.url).to be_nil }
|
20
|
+
it { expect(instance.file_name).to be_nil }
|
21
|
+
it { expect(instance.content_type).to be_nil }
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when requesting multiple locales at once' do
|
25
|
+
let(:asset_hash) { JSON.parse(File.read('fixtures/assets/nyancat_with_locales.json')) }
|
26
|
+
|
27
|
+
it { expect(instance.title).to eq 'Nyan Cat' }
|
28
|
+
it { expect(instance.description).to eq '' }
|
29
|
+
it { expect(instance.url).to eq '//images.ctfassets.net/cfexampleapi/4gp6taAwW4CmSgumq2ekUm/9da0cd1936871b8d72343e895a00d611/Nyan_cat_250px_frame.png' }
|
30
|
+
it { expect(instance.file_name).to eq 'Nyan_cat_250px_frame.png' }
|
31
|
+
it { expect(instance.content_type).to eq 'image/png' }
|
32
|
+
it { expect(instance.title(locale: 'tlh')).to eq "Nyan vIghro'" }
|
33
|
+
it { expect(instance.description(locale: 'tlh')).to eq '' }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#contentful_link' do
|
38
|
+
subject { instance.contentful_link }
|
39
|
+
|
40
|
+
it { is_expected.to eq 'https://app.contentful.com/spaces/cfexampleapi/assets/nyancat' }
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'serializing' do
|
44
|
+
subject { Marshal.load(Marshal.dump(instance)) }
|
45
|
+
|
46
|
+
it { expect(subject.id).to eq(instance.id) }
|
47
|
+
it { expect(subject.created_at).to eq(instance.created_at) }
|
48
|
+
it { expect(subject.updated_at).to eq(instance.updated_at) }
|
49
|
+
it { expect(subject.retrieved_at).to eq(instance.retrieved_at) }
|
50
|
+
it { expect(subject.locale).to eq(instance.locale) }
|
51
|
+
it { expect(subject.revision).to eq(instance.revision) }
|
52
|
+
it { expect(subject.space_id).to eq(instance.space_id) }
|
53
|
+
it { expect(subject.environment_id).to eq(instance.environment_id) }
|
54
|
+
it { expect(subject.title).to eq(instance.title) }
|
55
|
+
it { expect(subject.description).to eq(instance.description) }
|
56
|
+
it { expect(subject.file_name).to eq(instance.file_name) }
|
57
|
+
it { expect(subject.content_type).to eq(instance.content_type) }
|
58
|
+
it { expect(subject.url).to eq(instance.url) }
|
59
|
+
it { expect(subject.file_details).to eq(instance.file_details) }
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe ContentfulLite::AssetsArray do
|
4
|
+
let(:response) { JSON.parse(File.read('fixtures/assets/all.json')) }
|
5
|
+
let(:instance) { ContentfulLite::AssetsArray.new(response) }
|
6
|
+
|
7
|
+
describe 'should create an array of assets' do
|
8
|
+
it { expect(instance.first).to be_an ContentfulLite::Asset }
|
9
|
+
it { expect(instance.last).to be_an ContentfulLite::Asset }
|
10
|
+
it { expect(instance.sample).to be_an ContentfulLite::Asset }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'with multiple locales' do
|
14
|
+
let(:response) { JSON.parse(File.read('fixtures/assets/all_with_locales.json')) }
|
15
|
+
|
16
|
+
describe 'should create an array of assets' do
|
17
|
+
it { expect(instance.first).to be_an ContentfulLite::Asset }
|
18
|
+
it { expect(instance.first.title).to be_a String }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'serializing' do
|
23
|
+
subject { Marshal.load(Marshal.dump(instance)) }
|
24
|
+
|
25
|
+
it { expect(subject.first.id).to eq(instance.first.id) }
|
26
|
+
it { expect(subject.first.file_name).to eq(instance.first.file_name) }
|
27
|
+
it { expect(subject.last.file_details).to eq(instance.last.file_details) }
|
28
|
+
it { expect(subject.last.id).to eq(instance.last.id) }
|
29
|
+
it { expect(subject.last.file_name).to eq(instance.last.file_name) }
|
30
|
+
it { expect(subject.last.file_details).to eq(instance.last.file_details) }
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe ContentfulLite::BaseArray do
|
4
|
+
let(:instance) { ContentfulLite::BaseArray.new(response) }
|
5
|
+
|
6
|
+
describe '#attributes' do
|
7
|
+
context 'for an array of assets' do
|
8
|
+
let(:response) { JSON.parse(File.read('fixtures/assets/all.json')) }
|
9
|
+
|
10
|
+
it { expect(instance.total).to eq 4 }
|
11
|
+
it { expect(instance.skip).to eq 0 }
|
12
|
+
it { expect(instance.limit).to eq 100 }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#attributes' do
|
17
|
+
context 'for an array of entries' do
|
18
|
+
let(:response) { JSON.parse(File.read('fixtures/entries/all.json')) }
|
19
|
+
|
20
|
+
it { expect(instance.total).to eq 10 }
|
21
|
+
it { expect(instance.skip).to eq 0 }
|
22
|
+
it { expect(instance.limit).to eq 100 }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe ContentfulLite::Client do
|
4
|
+
let(:instance) { ContentfulLite::Client.new(space_id: 'cfexampleapi', access_token: 'b4c0n73n7fu1') }
|
5
|
+
|
6
|
+
around(:each) do |example|
|
7
|
+
if defined?(cassette_name)
|
8
|
+
VCR.use_cassette("client/#{cassette_name}") do
|
9
|
+
example.run
|
10
|
+
end
|
11
|
+
else
|
12
|
+
example.run
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#entries' do
|
17
|
+
let(:cassette_name) { 'entries' }
|
18
|
+
let(:query) { {} }
|
19
|
+
subject do
|
20
|
+
instance.entries(query)
|
21
|
+
end
|
22
|
+
|
23
|
+
it { is_expected.to be_a(ContentfulLite::EntriesArray) }
|
24
|
+
|
25
|
+
context 'when the query is invalid' do
|
26
|
+
let(:cassette_name) { 'invalid_query' }
|
27
|
+
let(:query) { { invalid_parameter: 'invalid_value' } }
|
28
|
+
|
29
|
+
it { expect { subject }.to raise_error(ContentfulLite::Client::RequestError, "InvalidQuery: The query you sent was invalid. Probably a filter or ordering specification is not applicable to the type of a field.") }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when the query has an array parameter' do
|
33
|
+
let(:cassette_name) { 'array_parameter' }
|
34
|
+
let(:query) { { 'sys.id[in]': ['nyancat', 'happycat'] } }
|
35
|
+
|
36
|
+
it { is_expected.to be_a(ContentfulLite::EntriesArray) }
|
37
|
+
it { expect(subject.size).to eq 2 }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#entry' do
|
42
|
+
let(:cassette_name) { 'entry' }
|
43
|
+
let(:query) { {} }
|
44
|
+
let(:entry_id) { 'nyancat' }
|
45
|
+
subject do
|
46
|
+
instance.entry(entry_id, query)
|
47
|
+
end
|
48
|
+
|
49
|
+
it { is_expected.to be_a(ContentfulLite::Entry) }
|
50
|
+
|
51
|
+
context 'when the query is invalid' do
|
52
|
+
let(:cassette_name) { 'entry_invalid_query' }
|
53
|
+
let(:query) { { locale: 'invalid_value' } }
|
54
|
+
|
55
|
+
it { expect { subject }.to raise_error(ContentfulLite::Client::RequestError, "BadRequest: Unknown locale: invalid_value") }
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when the id is not found' do
|
59
|
+
let(:cassette_name) { 'entry_missings_id' }
|
60
|
+
let(:entry_id) { 'invalidcat' }
|
61
|
+
|
62
|
+
it { expect { subject }.to raise_error(ContentfulLite::Client::NotFoundError, "NotFound: The resource could not be found.") }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#assets' do
|
67
|
+
let(:cassette_name) { 'assets' }
|
68
|
+
let(:query) { {} }
|
69
|
+
subject do
|
70
|
+
instance.assets(query)
|
71
|
+
end
|
72
|
+
|
73
|
+
it { is_expected.to be_a(ContentfulLite::AssetsArray) }
|
74
|
+
|
75
|
+
context 'when the query is invalid' do
|
76
|
+
let(:cassette_name) { 'assets_invalid_query' }
|
77
|
+
let(:query) { { invalid_parameter: 'invalid_value' } }
|
78
|
+
|
79
|
+
it { expect { subject }.to raise_error(ContentfulLite::Client::RequestError, "InvalidQuery: The query you sent was invalid. Probably a filter or ordering specification is not applicable to the type of a field.") }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '#asset' do
|
84
|
+
let(:cassette_name) { 'asset' }
|
85
|
+
let(:query) { {} }
|
86
|
+
let(:asset_id) { 'nyancat' }
|
87
|
+
subject do
|
88
|
+
instance.asset(asset_id, query)
|
89
|
+
end
|
90
|
+
|
91
|
+
it { is_expected.to be_a(ContentfulLite::Asset) }
|
92
|
+
|
93
|
+
context 'when the query is invalid' do
|
94
|
+
let(:cassette_name) { 'asset_invalid_query' }
|
95
|
+
let(:query) { { locale: 'invalid_value' } }
|
96
|
+
|
97
|
+
it { expect { subject }.to raise_error(ContentfulLite::Client::RequestError, "BadRequest: Unknown locale: invalid_value") }
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when the id is not found' do
|
101
|
+
let(:cassette_name) { 'asset_missings_id' }
|
102
|
+
let(:asset_id) { 'invalidcat' }
|
103
|
+
|
104
|
+
it { expect { subject }.to raise_error(ContentfulLite::Client::NotFoundError, "NotFound: The resource could not be found.") }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '#build_resource' do
|
109
|
+
let(:fixture) { 'entries/nyancat' }
|
110
|
+
let(:hash) { JSON.parse(File.read("fixtures/#{fixture}.json")) }
|
111
|
+
subject do
|
112
|
+
instance.build_resource(hash)
|
113
|
+
end
|
114
|
+
|
115
|
+
it { is_expected.to be_a(ContentfulLite::Entry) }
|
116
|
+
|
117
|
+
context 'when the resource is an asset' do
|
118
|
+
let(:fixture) { 'assets/nyancat' }
|
119
|
+
|
120
|
+
it { is_expected.to be_a(ContentfulLite::Asset) }
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'when the resource is a DeletedEntry' do
|
124
|
+
let(:fixture) { 'entries/deleted_entry' }
|
125
|
+
|
126
|
+
it { is_expected.to be_a(ContentfulLite::DeletedEntry) }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe ContentfulLite::CommonData do
|
4
|
+
let(:klass) { Class.new.include(described_class) }
|
5
|
+
let(:instance) { klass.new(raw_hash) }
|
6
|
+
|
7
|
+
describe '#attributes' do
|
8
|
+
context 'with an entry' do
|
9
|
+
let(:raw_hash) { JSON.parse(File.read('fixtures/entries/nyancat.json')) }
|
10
|
+
|
11
|
+
it { expect(instance.id).to eq 'nyancat' }
|
12
|
+
it { expect(instance.created_at).to eq DateTime.new(2013, 6, 27, 22, 46, 19.513) }
|
13
|
+
it { expect(instance.updated_at).to eq DateTime.new(2013, 9, 4, 9, 19, 39.027) }
|
14
|
+
it { expect(instance.locale).to eq 'en-US' }
|
15
|
+
it { expect(instance.revision).to eq 5 }
|
16
|
+
it { expect(instance.space_id).to eq 'cfexampleapi' }
|
17
|
+
it { expect(instance.environment_id).to eq 'master' }
|
18
|
+
it { expect(instance.retrieved_at).to be_a DateTime }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#attributes' do
|
23
|
+
context 'with an asset' do
|
24
|
+
let(:raw_hash) { JSON.parse(File.read('fixtures/assets/nyancat.json')) }
|
25
|
+
|
26
|
+
it { expect(instance.id).to eq 'nyancat' }
|
27
|
+
it { expect(instance.created_at).to eq DateTime.new(2013, 9, 2, 14, 56, 34.240) }
|
28
|
+
it { expect(instance.updated_at).to eq DateTime.new(2013, 9, 2, 14, 56, 34.240) }
|
29
|
+
it { expect(instance.locale).to eq 'en-US' }
|
30
|
+
it { expect(instance.revision).to eq 1 }
|
31
|
+
it { expect(instance.space_id).to eq 'cfexampleapi' }
|
32
|
+
it { expect(instance.environment_id).to eq 'master' }
|
33
|
+
it { expect(instance.retrieved_at).to be_a DateTime }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#fields' do
|
38
|
+
subject { instance.fields['name'] }
|
39
|
+
|
40
|
+
context 'for a single locale entry' do
|
41
|
+
let(:raw_hash) { JSON.parse(File.read('fixtures/entries/nyancat.json')) }
|
42
|
+
|
43
|
+
it { is_expected.to eq 'Nyan Cat' }
|
44
|
+
|
45
|
+
context 'when specific locale is requested' do
|
46
|
+
subject { instance.fields(locale: 'tlh')['name'] }
|
47
|
+
|
48
|
+
it { is_expected.to eq nil }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'for a multiple locale entry' do
|
53
|
+
let(:raw_hash) { JSON.parse(File.read('fixtures/entries/nyancat_with_locales.json')) }
|
54
|
+
|
55
|
+
it { is_expected.to eq 'Nyan Cat' }
|
56
|
+
|
57
|
+
context 'when specific locale is requested' do
|
58
|
+
subject { instance.fields(locale: 'tlh')['name'] }
|
59
|
+
|
60
|
+
it { is_expected.to eq "Nyan vIghro'" }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#with_locale' do
|
66
|
+
subject { instance.with_locale('tlh') { instance.fields['name'] } }
|
67
|
+
|
68
|
+
context 'for a multiple locale entry' do
|
69
|
+
let(:raw_hash) { JSON.parse(File.read('fixtures/entries/nyancat_with_locales.json')) }
|
70
|
+
|
71
|
+
it { is_expected.to eq "Nyan vIghro'" }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#to_link' do
|
76
|
+
let(:raw_hash) { JSON.parse(File.read('fixtures/entries/nyancat.json')) }
|
77
|
+
|
78
|
+
subject { instance.to_link }
|
79
|
+
|
80
|
+
it { expect(subject.id).to eq 'nyancat' }
|
81
|
+
it { expect(subject.type).to eq :entry }
|
82
|
+
|
83
|
+
context 'with an asset' do
|
84
|
+
let(:raw_hash) { JSON.parse(File.read('fixtures/assets/nyancat.json')) }
|
85
|
+
|
86
|
+
it { expect(subject.id).to eq 'nyancat' }
|
87
|
+
it { expect(subject.type).to eq :asset }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#as_json' do
|
92
|
+
let(:raw_hash) { JSON.parse(File.read('fixtures/entries/nyancat.json')) }
|
93
|
+
|
94
|
+
subject { instance.as_json }
|
95
|
+
|
96
|
+
it { is_expected.to eq(raw_hash) }
|
97
|
+
|
98
|
+
context 'when rails is passing some other parameters as hash' do
|
99
|
+
let(:hash) { { template: "something", status: 200 } }
|
100
|
+
subject { instance.as_json(hash) }
|
101
|
+
|
102
|
+
it { is_expected.to eq(raw_hash) }
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when rails is passing parameters with named args syntax' do
|
106
|
+
subject { instance.as_json(template: "something", status: 200) }
|
107
|
+
|
108
|
+
it { is_expected.to eq(raw_hash) }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe ContentfulLite::DeletedEntry do
|
4
|
+
let(:entry_hash) { JSON.parse(File.read('fixtures/entries/deleted_entry.json')) }
|
5
|
+
let(:instance) { ContentfulLite::DeletedEntry.new(entry_hash) }
|
6
|
+
|
7
|
+
describe '#attributes' do
|
8
|
+
it { expect(instance.content_type_id).to eq 'cat' }
|
9
|
+
it { expect(instance.id).to eq 'deletedcat' }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#contentful_link' do
|
13
|
+
subject { instance.contentful_link }
|
14
|
+
|
15
|
+
it { expect { subject }.to raise_error NotImplementedError }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'serializing' do
|
19
|
+
subject { Marshal.load(Marshal.dump(instance)) }
|
20
|
+
|
21
|
+
it { expect(subject.id).to eq(instance.id) }
|
22
|
+
it { expect(subject.created_at).to eq(instance.created_at) }
|
23
|
+
it { expect(subject.updated_at).to eq(instance.updated_at) }
|
24
|
+
it { expect(subject.retrieved_at).to eq(instance.retrieved_at) }
|
25
|
+
it { expect(subject.revision).to eq(instance.revision) }
|
26
|
+
it { expect(subject.space_id).to eq(instance.space_id) }
|
27
|
+
it { expect(subject.environment_id).to eq(instance.environment_id) }
|
28
|
+
it { expect(subject.content_type_id).to eq(instance.content_type_id) }
|
29
|
+
end
|
30
|
+
end
|