contentful_lite 1.0.2
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.
- 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
|