assetable 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +181 -0
- data/Rakefile +23 -0
- data/app/assets/images/assetable/icon-upload.png +0 -0
- data/app/assets/images/assetable/icons/icon-ai.png +0 -0
- data/app/assets/images/assetable/icons/icon-css.png +0 -0
- data/app/assets/images/assetable/icons/icon-desmos.png +0 -0
- data/app/assets/images/assetable/icons/icon-doc.png +0 -0
- data/app/assets/images/assetable/icons/icon-document.png +0 -0
- data/app/assets/images/assetable/icons/icon-docx.png +0 -0
- data/app/assets/images/assetable/icons/icon-eps.png +0 -0
- data/app/assets/images/assetable/icons/icon-flash.png +0 -0
- data/app/assets/images/assetable/icons/icon-html.png +0 -0
- data/app/assets/images/assetable/icons/icon-jpg.png +0 -0
- data/app/assets/images/assetable/icons/icon-js.png +0 -0
- data/app/assets/images/assetable/icons/icon-mov.png +0 -0
- data/app/assets/images/assetable/icons/icon-mp3.png +0 -0
- data/app/assets/images/assetable/icons/icon-mp4.png +0 -0
- data/app/assets/images/assetable/icons/icon-pdf.png +0 -0
- data/app/assets/images/assetable/icons/icon-php.png +0 -0
- data/app/assets/images/assetable/icons/icon-png.png +0 -0
- data/app/assets/images/assetable/icons/icon-ppt.png +0 -0
- data/app/assets/images/assetable/icons/icon-pptx.png +0 -0
- data/app/assets/images/assetable/icons/icon-txt.png +0 -0
- data/app/assets/images/assetable/icons/icon-xls.png +0 -0
- data/app/assets/images/assetable/icons/icon-xlsx.png +0 -0
- data/app/assets/images/assetable/icons/icon-xml.png +0 -0
- data/app/assets/javascripts/assetable/asset_gallery.js.coffee +74 -0
- data/app/assets/javascripts/assetable/assetable_uploader.js.coffee +204 -0
- data/app/assets/javascripts/assetable/gallery.js.coffee +33 -0
- data/app/assets/javascripts/assetable/uploader.js.coffee +10 -0
- data/app/assets/javascripts/vendor/bootstrap-modal.js +246 -0
- data/app/assets/javascripts/vendor/jquery-ui-1.10.3.custom.js +2252 -0
- data/app/assets/stylesheets/assetable/_assetable.css.sass +9 -0
- data/app/assets/stylesheets/assetable/_bootstrap.css.sass +5 -0
- data/app/assets/stylesheets/assetable/components/_buttons.css.sass +99 -0
- data/app/assets/stylesheets/assetable/components/_close.css.sass +28 -0
- data/app/assets/stylesheets/assetable/components/_forms.css.sass +219 -0
- data/app/assets/stylesheets/assetable/components/_gallery.css.sass +118 -0
- data/app/assets/stylesheets/assetable/components/_modals.css.sass +116 -0
- data/app/assets/stylesheets/assetable/components/_progress.css.sass +91 -0
- data/app/assets/stylesheets/assetable/components/_uploader.css.sass +175 -0
- data/app/assets/stylesheets/assetable/core/_mixins.css.sass +754 -0
- data/app/assets/stylesheets/assetable/core/_utilities.css.sass +5 -0
- data/app/assets/stylesheets/assetable/core/_variables.css.sass +165 -0
- data/app/controllers/assetable/assets_controller.rb +38 -0
- data/app/controllers/assetable/external_services_controller.rb +36 -0
- data/app/models/asset.rb +53 -0
- data/app/models/asset_attachment.rb +4 -0
- data/app/models/document.rb +5 -0
- data/app/models/external_service.rb +14 -0
- data/app/models/gallery.rb +7 -0
- data/app/models/image.rb +5 -0
- data/app/models/video.rb +5 -0
- data/app/uploaders/document_uploader.rb +50 -0
- data/app/uploaders/image_uploader.rb +67 -0
- data/app/uploaders/video_uploader.rb +40 -0
- data/app/views/assetable/assets/_asset.html.haml +20 -0
- data/app/views/assetable/assets/_gallery.html.haml +12 -0
- data/app/views/assetable/external_services/new.html.haml +31 -0
- data/config/initializers/carrierwave.rb +6 -0
- data/config/initializers/gallery_input.rb +37 -0
- data/config/initializers/uploader_input.rb +80 -0
- data/config/routes.rb +8 -0
- data/db/migrate/20131122232735_create_assets.rb +19 -0
- data/db/migrate/20131123172825_create_asset_attachments.rb +15 -0
- data/db/migrate/20131125200943_create_galleries.rb +14 -0
- data/lib/assetable.rb +18 -0
- data/lib/assetable/config.rb +23 -0
- data/lib/assetable/core.rb +41 -0
- data/lib/assetable/engine.rb +15 -0
- data/lib/assetable/version.rb +3 -0
- data/lib/tasks/assetable_tasks.rake +4 -0
- data/test/fixtures/asset_attachments.yml +11 -0
- data/test/fixtures/assets.yml +11 -0
- data/test/fixtures/images.yml +11 -0
- data/test/fixtures/videos.yml +11 -0
- data/test/models/asset_attachment_test.rb +7 -0
- data/test/models/asset_test.rb +7 -0
- data/test/models/image_test.rb +7 -0
- data/test/models/video_test.rb +7 -0
- metadata +371 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
class VideoUploader < CarrierWave::Uploader::Base
|
2
|
+
|
3
|
+
storage Assetable.storage
|
4
|
+
|
5
|
+
# Override the directory where uploaded files will be stored.
|
6
|
+
# This is a sensible default for uploaders that are meant to be mounted:
|
7
|
+
def store_dir
|
8
|
+
if model.present?
|
9
|
+
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
|
10
|
+
else
|
11
|
+
"uploads/#{mounted_as}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Create an MP4 version
|
16
|
+
# version :mp4 do
|
17
|
+
# process :encode_video => [:mp4, resolution: "1280x720", custom: "-preset medium"]
|
18
|
+
# end
|
19
|
+
|
20
|
+
# version :ogv, :from_version => :mp4 do
|
21
|
+
# process :encode_ogv => [resolution: :same]
|
22
|
+
# end
|
23
|
+
|
24
|
+
# # Create a thumbnail
|
25
|
+
# version :gallery_thumb do
|
26
|
+
# process thumbnail: [{format: 'jpg', quality: 10, size: "100x100", strip: true, logger: Rails.logger}]
|
27
|
+
# def full_filename for_file
|
28
|
+
# png_name for_file, version_name
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
|
32
|
+
def png_name for_file, version_name
|
33
|
+
%Q{#{version_name}_#{for_file.chomp(File.extname(for_file))}.jpg}
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_url
|
37
|
+
ActionController::Base.helpers.asset_path("assetable/" + [version_name, "video.png"].compact.join('_'))
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
.uploader-preview
|
2
|
+
|
3
|
+
= link_to asset.filename.to_s, target: "_blank" do
|
4
|
+
- if asset.image?
|
5
|
+
= image_tag asset.filename.preview.to_s, class: "uploader-preview"
|
6
|
+
- elsif asset.document?
|
7
|
+
= image_tag "assetable/icons/icon-#{asset.extension}.png", class: "uploader-preview"
|
8
|
+
- elsif asset.video?
|
9
|
+
= image_tag "assetable/icons/icon-mp4.png", class: "uploader-preview"
|
10
|
+
- elsif asset.external_service?
|
11
|
+
= image_tag "assetable/icons/icon-document.png", class: "uploader-preview"
|
12
|
+
|
13
|
+
%span.uploader-name= asset.name
|
14
|
+
.uploader-size-and-actions
|
15
|
+
%span.uploader-size= number_to_human_size(asset.file_size)
|
16
|
+
.uploader-actions
|
17
|
+
= link_to "delete", "#", class: "btn-uploader btn-uploader-remove-asset"
|
18
|
+
= link_to "edit", "#", class: "btn-uploader btn-uploader-edit-asset"
|
19
|
+
|
20
|
+
= hidden_field_tag(fieldname, asset.id)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
.assetable-gallery-header
|
2
|
+
%h3 Gallery
|
3
|
+
= link_to "×".html_safe, "#", class: "pull-right btn-close-assetable-gallery"
|
4
|
+
|
5
|
+
.assetable-gallery
|
6
|
+
= render partial: 'asset', collection: assets, locals: {fieldname: fieldname}
|
7
|
+
|
8
|
+
.assetable-gallery-footer
|
9
|
+
.assetable-gallery-paginate.pull-left
|
10
|
+
= paginate assets, remote: true
|
11
|
+
.pull-right
|
12
|
+
= link_to "insert asset", "#", class: "btn btn-primary btn-insert-asset"
|
@@ -0,0 +1,31 @@
|
|
1
|
+
.assetable-external-services.assetable-modal.modal.fade
|
2
|
+
.modal-dialog
|
3
|
+
.modal-content
|
4
|
+
= form_for [:assetable, @external_service], remote: true do |f|
|
5
|
+
.modal-header
|
6
|
+
%button.close{"aria-hidden" => "true", "data-dismiss" => "modal", type: "button"} ×
|
7
|
+
%h4.modal-title Third Party Service
|
8
|
+
.modal-body
|
9
|
+
|
10
|
+
= hidden_field_tag :fieldname, params[:fieldname]
|
11
|
+
|
12
|
+
.form-group
|
13
|
+
= f.label :name
|
14
|
+
= f.text_field :name, class: "form-control inpu-fluid", required: true
|
15
|
+
.form-group
|
16
|
+
= f.label :content_type
|
17
|
+
= f.select :content_type, ExternalService.possible_content_types
|
18
|
+
.form-group
|
19
|
+
= f.label :body
|
20
|
+
= f.text_area :body, class: "form-control input-fluid", required: true
|
21
|
+
.form-group.row
|
22
|
+
.col-xs-6
|
23
|
+
= f.label :width
|
24
|
+
= f.number_field :width, class: "form-control input-fluid"
|
25
|
+
.col-xs-6
|
26
|
+
= f.label :height
|
27
|
+
= f.number_field :height, class: "form-control input-fluid"
|
28
|
+
|
29
|
+
.modal-footer
|
30
|
+
= button_tag "Cancel", class: "btn btn-default", :'data-dismiss' => "modal", type: "button"
|
31
|
+
= f.submit "Add Third Party Service", class: "btn btn-primary"
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class ActionView::Helpers::FormBuilder
|
2
|
+
|
3
|
+
include ActionView::Helpers::Tags
|
4
|
+
include ActionView::Helpers::TagHelper
|
5
|
+
include ActionView::Helpers::FormTagHelper
|
6
|
+
include ActionView::Helpers::FormOptionsHelper
|
7
|
+
include ActionView::Helpers::CaptureHelper
|
8
|
+
include ActionView::Helpers::AssetTagHelper
|
9
|
+
include ActionView::Helpers::NumberHelper
|
10
|
+
|
11
|
+
def gallery method, options = {}
|
12
|
+
# Build the association
|
13
|
+
@object.send("build_#{method}") unless @object.present? and @object.send(method).present?
|
14
|
+
# ID of the input wrapper
|
15
|
+
options[:id] = field_id(method, options[:index])
|
16
|
+
# The fieldname for the association
|
17
|
+
fieldname = @object_name + "[#{method}_attributes][asset_ids][]"
|
18
|
+
|
19
|
+
# Add the asset preview or the empty preview div
|
20
|
+
if gallery = @object.send(method)
|
21
|
+
asset_preview = ""
|
22
|
+
gallery.assets.each do |a|
|
23
|
+
asset_preview += asset_html(a, fieldname)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
asset_preview = content_tag(:div, "", class: "uploader-preview")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Uploader HTML with the asset previews and actions
|
30
|
+
uploader_html = content_tag(:div, (asset_preview.html_safe), class: "uploadar-data-wrapper")
|
31
|
+
|
32
|
+
# Wrap the previews and uploader in a div
|
33
|
+
uploader_wrapper = content_tag(:div, uploader_html, class: "gallery-uploader", id: options[:id], :'data-uploader-input-name' => fieldname)
|
34
|
+
return uploader_wrapper
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
class ActionView::Helpers::FormBuilder
|
2
|
+
|
3
|
+
include ActionView::Helpers::TagHelper
|
4
|
+
include ActionView::Helpers::FormTagHelper
|
5
|
+
include ActionView::Helpers::FormOptionsHelper
|
6
|
+
include ActionView::Helpers::CaptureHelper
|
7
|
+
include ActionView::Helpers::AssetTagHelper
|
8
|
+
include ActionView::Helpers::NumberHelper
|
9
|
+
|
10
|
+
def uploader method, options = {}
|
11
|
+
# add an ID to the options
|
12
|
+
options[:id] = field_id(method, options[:index]) unless options[:id].present?
|
13
|
+
|
14
|
+
# Set the fieldname
|
15
|
+
fieldname = @object_name + "[#{method}_association_attributes][asset_id]"
|
16
|
+
|
17
|
+
# Create the uploader
|
18
|
+
value = @object.nil? ? nil : @object.send(method)
|
19
|
+
|
20
|
+
# Add the asset preview or the empty preview div
|
21
|
+
if asset = asset_record(method)
|
22
|
+
asset_preview = asset_html(asset, fieldname)
|
23
|
+
else
|
24
|
+
asset_preview = content_tag(:div, "", class: "uploader-preview")
|
25
|
+
end
|
26
|
+
|
27
|
+
# uploaer html with preview and input
|
28
|
+
uploader_html = content_tag(:div, (asset_preview), class: "uploader-data-wrapper")
|
29
|
+
|
30
|
+
# Create and return the uploader html
|
31
|
+
uploader_wrapper = content_tag(:div, uploader_html, class: "uploader #{'uploader-has-asset' if asset} #{options[:class]}", id: options[:id], :'data-uploader-input-name' => fieldname)
|
32
|
+
return uploader_wrapper
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
# Convenience method to create the asset html
|
37
|
+
def asset_html asset, fieldname
|
38
|
+
image_tag = asset_preview_image(asset)
|
39
|
+
asset_name = content_tag(:span, asset.name.to_s, class: "uploader-name")
|
40
|
+
asset_size = content_tag(:span, number_to_human_size(asset.file_size.to_s), class: "uploader-size")
|
41
|
+
asset_size_and_actions = content_tag(:div, (asset_size + asset_actions), class: "uploader-size-and-actions")
|
42
|
+
field = hidden_field_tag(fieldname, (asset.id))
|
43
|
+
return content_tag(:div, (image_tag + asset_name + asset_size_and_actions + field), class: "uploader-preview")
|
44
|
+
end
|
45
|
+
|
46
|
+
# Asset preview image or fallback to a content type image
|
47
|
+
def asset_preview_image asset
|
48
|
+
if asset.image?
|
49
|
+
preview_image_tag = image_tag(asset.filename.preview.to_s, class: "uploader-preview")
|
50
|
+
elsif asset.document?
|
51
|
+
preview_image_tag = image_tag(ActionController::Base.helpers.asset_path("assetable/icons/icon-#{asset.extension}.png"), class: "uploader-preview")
|
52
|
+
elsif asset.video?
|
53
|
+
preview_image_tag = image_tag(ActionController::Base.helpers.asset_path("assetable/icons/icon-mp4.png"), class: "uploader-preview")
|
54
|
+
elsif asset.external_service?
|
55
|
+
preview_image_tag = image_tag(ActionController::Base.helpers.asset_path("assetable/icons/icon-document.png"), class: "uploader-preview")
|
56
|
+
end
|
57
|
+
|
58
|
+
return link_to preview_image_tag, asset.filename.to_s, target: "_blank"
|
59
|
+
end
|
60
|
+
|
61
|
+
# Asset actions, i.e.e remove and edit buttons
|
62
|
+
def asset_actions
|
63
|
+
remove_btn = link_to "delete", "#", class: "btn-uploader btn-uploader-remove-asset"
|
64
|
+
edit_btn = link_to "edit", "#", class: "btn-uploader btn-uploader-edit-asset"
|
65
|
+
content_tag(:div, (remove_btn + edit_btn), class: "uploader-actions")
|
66
|
+
end
|
67
|
+
|
68
|
+
# Get the asset record, if it's a belongs_to assocation, then we
|
69
|
+
# can grab the actual record
|
70
|
+
def asset_record method
|
71
|
+
@object.send(method) rescue nil
|
72
|
+
end
|
73
|
+
|
74
|
+
# Get the field id
|
75
|
+
def field_id label, index=nil
|
76
|
+
output = index ? "_#{index}" : ''
|
77
|
+
return @object_name + output + "_#{label}"
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateAssets < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :assets do |t|
|
4
|
+
t.string :type
|
5
|
+
t.string :name
|
6
|
+
t.text :body
|
7
|
+
t.string :filename
|
8
|
+
t.string :checksum
|
9
|
+
t.string :path
|
10
|
+
t.string :content_type
|
11
|
+
t.integer :file_size
|
12
|
+
t.integer :width
|
13
|
+
t.integer :height
|
14
|
+
t.integer :duration
|
15
|
+
t.integer :bit_rate
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateAssetAttachments < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :asset_attachments do |t|
|
4
|
+
t.references :asset
|
5
|
+
t.references :assetable, :polymorphic => true
|
6
|
+
t.string :name
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
add_index :asset_attachments, :asset_id
|
11
|
+
add_index :asset_attachments, [:assetable_type, :assetable_id]
|
12
|
+
add_index :asset_attachments, [:assetable_type, :assetable_id, :name], unique: true, name: "named_asset"
|
13
|
+
add_index :asset_attachments, :assetable_id
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateGalleries < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :galleries do |t|
|
4
|
+
t.references :galleryable, :polymorphic => true
|
5
|
+
t.string :name
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
|
9
|
+
add_index :galleries, [:galleryable_type, :galleryable_id]
|
10
|
+
add_index :galleries, [:galleryable_type, :galleryable_id, :name], unique: true, name: "named_gallery"
|
11
|
+
|
12
|
+
add_index :galleries, :galleryable_id
|
13
|
+
end
|
14
|
+
end
|
data/lib/assetable.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "carrierwave"
|
2
|
+
require "fog"
|
3
|
+
require "plupload-rails"
|
4
|
+
require "kaminari"
|
5
|
+
|
6
|
+
require "haml-rails"
|
7
|
+
require "sass-rails"
|
8
|
+
require "jquery-rails"
|
9
|
+
|
10
|
+
require "assetable/core"
|
11
|
+
require "assetable/engine"
|
12
|
+
require "assetable/config"
|
13
|
+
|
14
|
+
module Assetable
|
15
|
+
|
16
|
+
extend Config
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Assetable
|
2
|
+
module Config
|
3
|
+
|
4
|
+
VALID_OPTION_KEYS = [
|
5
|
+
:storage,
|
6
|
+
:external_document_types
|
7
|
+
]
|
8
|
+
|
9
|
+
attr_accessor *VALID_OPTION_KEYS
|
10
|
+
|
11
|
+
def configure
|
12
|
+
yield self
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def options
|
17
|
+
options = {}
|
18
|
+
VALID_OPTION_KEYS.each{ |pname| options[pname] = send(pname) }
|
19
|
+
options
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Assetable
|
2
|
+
module Core
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def assetable *args
|
10
|
+
if args.present?
|
11
|
+
args.each do |arg|
|
12
|
+
has_one :"#{arg}_association", -> { where(name: arg) }, class_name: "AssetAttachment", as: :assetable
|
13
|
+
has_one arg, through: :"#{arg}_association", source: :asset
|
14
|
+
accepts_nested_attributes_for :"#{arg}_association", allow_destroy: true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Galleries
|
20
|
+
def galleryable *args
|
21
|
+
# By default, let's include a gallery.
|
22
|
+
unless args.include? :gallery
|
23
|
+
has_one :gallery, as: :galleryable, dependent: :destroy
|
24
|
+
accepts_nested_attributes_for :gallery
|
25
|
+
end
|
26
|
+
|
27
|
+
if args.present?
|
28
|
+
args.each do |arg|
|
29
|
+
has_one arg, -> { where(name: arg) }, class_name: "Gallery", as: :galleryable
|
30
|
+
accepts_nested_attributes_for arg
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module InstanceMethods
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
ActiveRecord::Base.send :include, Assetable::Core
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Assetable
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
config.generators.integration_tool :rspec
|
4
|
+
config.generators.test_framework :rspec
|
5
|
+
|
6
|
+
# Run the engine migrations with the main app rake task
|
7
|
+
initializer :append_migrations do |app|
|
8
|
+
unless app.root.to_s.match root.to_s
|
9
|
+
config.paths["db/migrate"].expanded.each do |expanded_path|
|
10
|
+
app.config.paths["db/migrate"] << expanded_path
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
|
2
|
+
|
3
|
+
# This model initially had no columns defined. If you add columns to the
|
4
|
+
# model remove the '{}' from the fixture names and add the columns immediately
|
5
|
+
# below each fixture, per the syntax in the comments below
|
6
|
+
#
|
7
|
+
one: {}
|
8
|
+
# column: value
|
9
|
+
#
|
10
|
+
two: {}
|
11
|
+
# column: value
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
|
2
|
+
|
3
|
+
# This model initially had no columns defined. If you add columns to the
|
4
|
+
# model remove the '{}' from the fixture names and add the columns immediately
|
5
|
+
# below each fixture, per the syntax in the comments below
|
6
|
+
#
|
7
|
+
one: {}
|
8
|
+
# column: value
|
9
|
+
#
|
10
|
+
two: {}
|
11
|
+
# column: value
|