better to_json handling for content entries and their matching liquid drops (WIP)

did committed Sep 11, 2015
commit 2eb5ea0821c7ac7eccdf8d35c46d5edbf5f94007
Showing 11 changed files with 161 additions and 15 deletions
locomotive/steam/decorators/i18n_decorator.rb b/lib/locomotive/steam/decorators/i18n_decorator.rb +16 -0
@@ @@ -84,6 +84,22 @@ module Locomotive
end
end
+ def to_hash
+ __getobj__.to_hash.tap do |hash|
+ @__localized_attributes__.keys.each do |name|
+ hash[name.to_s] = __get_localized_value__(name)
+ end
+ end
+ end
+
+ def as_json(options = nil)
+ to_hash.as_json(options)
+ end
+
+ def to_json
+ as_json.to_json
+ end
+
#:nocov:
def inspect
"[Decorated #{__getobj__.class.name}][I18n] attributes exist? " +
locomotive/steam/liquid/drops/base.rb b/lib/locomotive/steam/liquid/drops/base.rb +4 -0
@@ @@ -28,6 +28,10 @@ module Locomotive
records
end
+ def as_json(options = nil)
+ @_source.as_json(options)
+ end
+
protected
def liquify(*records, &block)
locomotive/steam/liquid/drops/content_entry_collection.rb b/lib/locomotive/steam/liquid/drops/content_entry_collection.rb +7 -1
@@ @@ -13,7 +13,13 @@ module Locomotive
end
def all
- collection
+ collection.map do |entry|
+ entry.to_liquid.tap do |drop|
+ if drop && drop.respond_to?(:context=)
+ drop.context = @context
+ end
+ end
+ end
end
def count
locomotive/steam/liquid/filters/json.rb b/lib/locomotive/steam/liquid/filters/json.rb +11 -14
@@ @@ -4,19 +4,15 @@ module Locomotive
module Filters
module Json
- def json(input, fields = nil)
+ def json(input, fields = [])
if fields && fields.is_a?(String)
fields = fields.split(',').map(&:strip)
end
- if fields.blank?
- input.to_json
- elsif input.respond_to?(:each)
- if fields.size == 1
- input.map { |object| object[fields.first].to_json }.join(',')
- else
- input.map { |object| "{" + object_to_json(object, fields) + "}" }.join(',')
- end
+ if input.respond_to?(:each)
+ input.map do |object|
+ fields.size == 1 ? object[fields.first].to_json : object_to_json(object, fields)
+ end.join(',')
else
object_to_json(input, fields)
end
@@ @@ -25,11 +21,12 @@ module Locomotive
protected
def object_to_json(input, fields)
- [].tap do |output|
- fields.each do |field|
- output << %("#{field}":#{input[field].to_json})
- end
- end.join(',')
+ if input.respond_to?(:as_json)
+ options = fields.blank? ? {} : { only: fields }
+ input.as_json(options).to_json
+ else
+ input.to_json
+ end
end
end
locomotive/steam/models.rb b/lib/locomotive/steam/models.rb +1 -0
@@ @@ -1,4 +1,5 @@
require_relative 'models/concerns/validation'
+ require_relative 'models/concerns/to_json'
require_relative 'models/i18n_field'
require_relative 'models/associations/embedded'
require_relative 'models/associations/referenced'
locomotive/steam/models/concerns/to_json.rb b/lib/locomotive/steam/models/concerns/to_json.rb +34 -0
@@ @@ -0,0 +1,34 @@
+ module Locomotive
+ module Steam
+ module Models
+ module Concerns
+
+ module ToJson
+
+ def to_hash
+ {}.tap do |_attributes|
+ attributes.each do |key, value|
+ next if value && value.respond_to?(:repository) # skip associations
+
+ _attributes[key] = (case value
+ when Locomotive::Steam::Models::I18nField then value.to_hash
+ else value
+ end)
+ end
+ end.stringify_keys
+ end
+
+ def as_json(options = nil)
+ to_hash.as_json(options)
+ end
+
+ def to_json
+ as_json.to_json
+ end
+
+ end
+
+ end
+ end
+ end
+ end
locomotive/steam/models/entity.rb b/lib/locomotive/steam/models/entity.rb +1 -0
@@ @@ -4,6 +4,7 @@ module Locomotive::Steam
module Entity
include Locomotive::Steam::Models::Concerns::Validation
+ include Locomotive::Steam::Models::Concerns::ToJson
attr_accessor :attributes, :associations, :localized_attributes, :base_url
locomotive/steam/models/i18n_field.rb b/lib/locomotive/steam/models/i18n_field.rb +2 -0
@@ @@ -36,6 +36,8 @@ module Locomotive::Steam
alias :__translations__ :translations
+ alias :to_hash :translations
+
def serialize(attributes)
attributes[@name] = @translations
end
spec/support/liquid.rb +4 -0
@@ @@ -18,6 +18,10 @@ module Liquid
def before_method(meth)
@_source[meth.to_sym]
end
+
+ def as_json(options = nil)
+ @_source.as_json(options)
+ end
end
class SimpleEventsListener
spec/unit/decorators/i18n_decorator_spec.rb +9 -0
@@ @@ -83,6 +83,15 @@ describe Locomotive::Steam::Decorators::I18nDecorator do
expect(decorated.__locale__).to eq :fr
end
+ describe '#to_hash' do
+
+ before { expect(page).to receive(:to_hash).and_return('title' => { 'en' => 'some stuff', 'fr' => 'some stuff' }) }
+ subject { decorated.to_hash }
+
+ it { expect(subject).to eq('title' => 'Bonjour monde', 'slug' => 'hello-world') }
+
+ end
+
def i18n_field(name, translations)
Locomotive::Steam::Models::I18nField.new(name, translations)
end
spec/unit/models/concerns/to_json_spec.rb +72 -0
@@ @@ -0,0 +1,72 @@
+ require 'spec_helper'
+
+ describe Locomotive::Steam::Models::Concerns::ToJson do
+
+ let(:attributes) { {} }
+ let(:entity) { SimpleEntity.new(attributes) }
+
+ describe '#to_hash' do
+
+ subject { entity.to_hash }
+
+ it { expect(subject).to eq({}) }
+
+ context 'simple attributes' do
+ let(:attributes) { { title: 'Hello world', published: true, tags: ['a', 'b'] } }
+ it { expect(subject).to eq('title' => 'Hello world', 'published' => true, 'tags' => ['a', 'b']) }
+ end
+
+ context 'localized attributes' do
+ let(:attributes) { { title: Locomotive::Steam::Models::I18nField.new(:title, { fr: 'Bonjour', en: 'Hi' })} }
+ it { expect(subject).to eq('title' => { 'fr' => 'Bonjour', 'en' => 'Hi' }) }
+ end
+
+ context 'referenced associations' do
+ let(:attributes) { { title: 'Lorem ipsum', author: instance_double('BelongsToAssociation', repository: true) } }
+ it { expect(subject).to eq('title' => 'Lorem ipsum') }
+ end
+
+ end
+
+ describe '#as_json' do
+
+ let(:options) { nil }
+
+ subject { entity.as_json(options) }
+
+ it { expect(subject).to eq({}) }
+
+ context 'with options' do
+
+ let(:options) { { only: ['title'] } }
+ let(:attributes) { { title: 'Hello world', body: 'Lorem ipsum' } }
+
+ it { expect(subject).to eq('title' => 'Hello world') }
+
+ end
+
+ end
+
+ describe '#to_json' do
+
+ subject { entity.to_json }
+
+ it { expect(subject).to eq('{}') }
+
+ context 'with attributes' do
+
+ let(:attributes) { { title: 'Hello world', published: true } }
+
+ it { expect(subject).to eq(%{{"title":"Hello world","published":true}}) }
+
+ end
+
+ end
+
+ class SimpleEntity
+ include Locomotive::Steam::Models::Concerns::ToJson
+ attr_reader :attributes
+ def initialize(attributes = {}); @attributes = attributes; end
+ end
+
+ end