Skip to content
This repository has been archived by the owner on May 8, 2024. It is now read-only.

Commit

Permalink
Add Individual Files per Entries Option (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
dlitvakb authored Apr 19, 2017
1 parent c2d3b0b commit b160a5e
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 44 deletions.
44 changes: 33 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,21 @@ contentful:
api_url: 'preview.contentful.com' # Defaults to 'api.contentful.com' which is Production
base_path: app_path # Optional - Defaults to Current directory
destination: destination_in_data # Optional - Defaults to _data/contentful/spaces
individual_entry_files: true # Optional - Defaults to false
```
Parameter | Description
---------- | ------------
space | Contentful Space ID
access_token | Contentful Delivery API access token
cda_query | Hash describing query configuration. See [contentful.rb](https://github.com/contentful/contentful.rb) for more info (look for filter options there). Note that by default only 100 entries will be fetched, this can be configured to up to 1000 entries using the `limit` option.
all_entries | Boolean, if true will run multiple queries to the API until it fetches all entries for the space
all_entries_page_size | Integer, the amount of maximum entries per CDA Request when fetching :all_entries
content_types | Hash describing the mapping applied to entries of the imported content types
client_options | Hash describing Contentful::Client configuration. See [contentful.rb](https://github.com/contentful/contentful.rb) for more info.
base_path | String with path to your Jekyll Application, defaults to current directory. Path is relative to your current location.
destination | String with path within `_data` under which to store the output yaml file. Defaults to contentful/spaces
Parameter | Description
---------- | ------------
space | Contentful Space ID
access_token | Contentful Delivery API access token
cda_query | Hash describing query configuration. See [contentful.rb](https://github.com/contentful/contentful.rb) for more info (look for filter options there). Note that by default only 100 entries will be fetched, this can be configured to up to 1000 entries using the `limit` option.
all_entries | Boolean, if true will run multiple queries to the API until it fetches all entries for the space
all_entries_page_size | Integer, the amount of maximum entries per CDA Request when fetching :all_entries
content_types | Hash describing the mapping applied to entries of the imported content types
client_options | Hash describing Contentful::Client configuration. See [contentful.rb](https://github.com/contentful/contentful.rb) for more info.
base_path | String with path to your Jekyll Application, defaults to current directory. Path is relative to your current location.
destination | String with path within `_data` under which to store the output yaml file. Defaults to contentful/spaces
individual_entry_files | Boolean, if true will create an individual file per entry separated in folders by content type, file path will be `{space_alias}/{content_type_id}/{entry_id}.yaml`. Default behavior is to create a file per space. Usage is affected when this is set to true, please look in the section below.

You can add multiple spaces to your configuration

Expand Down Expand Up @@ -157,6 +159,26 @@ therefore you can do the following:
This way, it is safe to share your code without having to worry
about your credentials.

### Using Multiple Entry Files

When setting the `individual_entry_files` flag to true, the usage pattern changes a little,
as Jekyll does not allow for variable unpacking when iterating.

A usage example is as follows:

```html
<ul class="cat-list">
<!-- Each element in the array of entries for a content type is an array of the form ['entry_id', { ... entry_data ...}] -->
{% for cat_data in site.data.contentful.spaces.example.cat %}
{% assign cat_id = cat_data[0] %} <!-- Entry ID is the first element of the array -->
{% assign cat = cat_data[1] %} <!-- Entry data is the second element of the array -->
<li>
<p>{{ cat_id }}: {{ cat.name }}</p>
</li>
{% endfor %}
</ul>
```

## Examples

You can find working examples of multiple uses [here](https://github.com/contentful/contentful_jekyll_examples).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@

module Jekyll
module Contentful
# Data Exporter Class
# Base Data Exporter Class
#
# Serializes Contentful data into YAML files
class DataExporter
DATA_FOLDER = '_data'.freeze
CONTENTFUL_FOLDER = 'contentful'.freeze
SPACES_FOLDER = 'spaces'.freeze

# Generic Data Exporter Implementation
class BaseDataExporter
attr_reader :name, :entries, :config

def initialize(name, entries, config = {})
Expand All @@ -19,16 +15,7 @@ def initialize(name, entries, config = {})
end

def run
setup_directory

File.open(destination_file, 'w') do |file|
file.write(
::Jekyll::Contentful::Serializer.new(
entries,
config
).to_yaml
)
end
raise 'must implement'
end

def base_directory
Expand All @@ -45,24 +32,34 @@ def base_directory

def destination_directory
destination_dir = File.join(
base_directory, DATA_FOLDER,
CONTENTFUL_FOLDER, SPACES_FOLDER
base_directory, data_folder,
contentful_folder, spaces_folder
)
if config.key?('destination')
destination_dir = File.join(
base_directory, DATA_FOLDER, config['destination']
base_directory, data_folder, config['destination']
)
end

destination_dir
end

def destination_file
File.join(destination_directory, "#{name}.yaml")
def setup_directory(directory)
FileUtils.mkdir_p(directory)
end

protected

def data_folder
'_data'
end

def contentful_folder
'contentful'
end

def setup_directory
FileUtils.mkdir_p destination_directory
def spaces_folder
'spaces'
end
end
end
Expand Down
33 changes: 30 additions & 3 deletions lib/jekyll-contentful-data-import/importer.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'contentful'
require 'jekyll-contentful-data-import/data_exporter'
require 'jekyll-contentful-data-import/single_file_data_exporter'
require 'jekyll-contentful-data-import/multi_file_data_exporter'

module Jekyll
module Contentful
Expand All @@ -26,9 +27,35 @@ def run
end

def export_data(name, space_client, options)
Jekyll::Contentful::DataExporter.new(
entries = get_entries(space_client, options)

if options.fetch('individual_entry_files', false)
export_data_multiple_files(
name,
entries,
options
)
else
export_data_single_file(
name,
entries,
options
)
end
end

def export_data_single_file(name, entries, options)
Jekyll::Contentful::SingleFileDataExporter.new(
name,
entries,
options
).run
end

def export_data_multiple_files(name, entries, options)
Jekyll::Contentful::MultiFileDataExporter.new(
name,
get_entries(space_client, options),
entries,
options
).run
end
Expand Down
35 changes: 35 additions & 0 deletions lib/jekyll-contentful-data-import/multi_file_data_exporter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require 'jekyll-contentful-data-import/base_data_exporter'
require 'yaml'

module Jekyll
module Contentful
# Single File Data Exporter Class
#
# Serializes Contentful data into a multiple YAML files
class MultiFileDataExporter < BaseDataExporter
def run
data = ::Jekyll::Contentful::Serializer.new(
entries,
config
).serialize

data.each do |content_type, entries|
content_type_directory = File.join(destination_directory, name, content_type.to_s)
setup_directory(content_type_directory)

entries.each do |entry|
yaml_entry = YAML.dump(entry)

File.open(destination_file(content_type_directory, entry), 'w') do |file|
file.write(yaml_entry)
end
end
end
end

def destination_file(content_type_directory, entry)
File.join(content_type_directory, "#{entry['sys']['id']}.yaml")
end
end
end
end
27 changes: 27 additions & 0 deletions lib/jekyll-contentful-data-import/single_file_data_exporter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require 'jekyll-contentful-data-import/base_data_exporter'

module Jekyll
module Contentful
# Single File Data Exporter Class
#
# Serializes Contentful data into a single YAML file
class SingleFileDataExporter < BaseDataExporter
def run
setup_directory(destination_directory)

File.open(destination_file, 'w') do |file|
file.write(
::Jekyll::Contentful::Serializer.new(
entries,
config
).to_yaml
)
end
end

def destination_file
File.join(destination_directory, "#{name}.yaml")
end
end
end
end
24 changes: 22 additions & 2 deletions spec/jekyll-contentful/importer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,35 @@ def run; end
allow(subject).to receive(:spaces).and_return([['foo', {'space' => 'foo', 'access_token' => 'bar'}], ['bar', {'space' => 'bar', 'access_token' => 'foo'}]])
allow(subject).to receive(:client).and_return(ClientDouble.new)

expect(Jekyll::Contentful::DataExporter).to receive(:new).and_return(ExporterDouble.new).twice
expect(Jekyll::Contentful::SingleFileDataExporter).to receive(:new).and_return(ExporterDouble.new).twice

subject.run
end

it 'runs exporter with correct arguments' do
allow(subject).to receive(:client).and_return(ClientDouble.new)

expect(Jekyll::Contentful::DataExporter).to receive(:new).with('example', [], config['spaces'].first['example']).and_return(ExporterDouble.new)
expect(Jekyll::Contentful::SingleFileDataExporter).to receive(:new).with('example', [], config['spaces'].first['example']).and_return(ExporterDouble.new)

subject.run
end

it 'runs multifile exporter when passed :individual_entry_files flag' do
config = {
'spaces' => [
{
'example' => {
'space' => 'cfexampleapi',
'access_token' => 'b4c0n73n7fu1',
'individual_entry_files' => true
}
}
]
}
subject = described_class.new(config)
allow(subject).to receive(:client).and_return(ClientDouble.new)

expect(Jekyll::Contentful::MultiFileDataExporter).to receive(:new).with('example', [], config['spaces'].first['example']).and_return(ExporterDouble.new)

subject.run
end
Expand Down
85 changes: 85 additions & 0 deletions spec/jekyll-contentful/multi_file_data_exporter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
require 'spec_helper'
require 'stringio'

describe Jekyll::Contentful::MultiFileDataExporter do
subject { described_class.new('foo', []) }

describe 'instance methods' do
describe '#base_directory' do
it 'default directory' do
expect(subject.base_directory).to eq(Dir.pwd)
end

it 'overridden directory' do
subject = described_class.new('foo', [], {'base_path' => 'foo_dir'})

expect(subject.base_directory).to eq(File.join(Dir.pwd, 'foo_dir'))
end
end

describe '#destination_directory' do
it 'default directory' do
expected = File.join(Dir.pwd, '_data', 'contentful', 'spaces')
expect(subject.destination_directory).to eq(expected)
end

it 'overridden directory' do
subject = described_class.new('foo', [], {'base_path' => 'foo_dir'})

expected = File.join(Dir.pwd, 'foo_dir', '_data', 'contentful', 'spaces')
expect(subject.destination_directory).to eq(expected)
end
end

it '#destination_file' do
entry_double = { 'sys' => { 'id' => 'bar' } }
expected = File.join('foo', 'bar.yaml')
expect(subject.destination_file('foo', entry_double)).to eq(expected)
end

describe '#setup_directory' do
it 'default directory' do
expected = File.join(Dir.pwd, '_data', 'contentful', 'spaces')
expect(FileUtils).to receive(:mkdir_p).with(expected)

subject.setup_directory(expected)
end

it 'overridden directory' do
subject = described_class.new('foo', [], {'base_path' => 'foo_dir'})

expected = File.join(Dir.pwd, 'foo_dir', '_data', 'contentful', 'spaces')
expect(FileUtils).to receive(:mkdir_p).with(expected)

subject.setup_directory(expected)
end
end

describe '#run' do
before do
allow(subject).to receive(:setup_directory)
end

it 'does nothing with no entries' do
subject.run
end

it 'serializes entries' do
expect_any_instance_of(::Jekyll::Contentful::Serializer).to receive(:serialize) { {} }

subject.run
end

it 'creates a file per entry' do
subject = described_class.new('foo', [EntryDouble.new('bar', ContentTypeDouble.new('bar_ct'))])

expected_directory_path = File.join(Dir.pwd, '_data', 'contentful', 'spaces', 'foo', 'bar_ct')
expect(FileUtils).to receive(:mkdir_p).with(expected_directory_path)
expect(File).to receive(:open).with(File.join(expected_directory_path, 'bar.yaml'), 'w')

subject.run
end
end
end
end

Loading

0 comments on commit b160a5e

Please sign in to comment.