shortcode 0.0.1
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.
- data/.gitignore +18 -0
- data/.rbenv-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +50 -0
- data/Rakefile +1 -0
- data/lib/shortcode.rb +34 -0
- data/lib/shortcode/exceptions.rb +9 -0
- data/lib/shortcode/parser.rb +39 -0
- data/lib/shortcode/tag.rb +48 -0
- data/lib/shortcode/transformer.rb +16 -0
- data/lib/shortcode/version.rb +3 -0
- data/shortcode.gemspec +28 -0
- data/spec/parser_spec.rb +235 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/fixtures.rb +7 -0
- data/spec/support/fixtures/complex_snippet.txt +13 -0
- data/spec/support/fixtures/complex_snippet_output.html +33 -0
- data/spec/support/fixtures/full_quote.txt +1 -0
- data/spec/support/fixtures/full_quote_output.html +7 -0
- data/spec/support/fixtures/quote_with_extras.txt +1 -0
- data/spec/support/fixtures/quote_with_extras_output.html +7 -0
- data/spec/support/fixtures/simple_list.txt +5 -0
- data/spec/support/fixtures/simple_list_output.html +15 -0
- data/spec/support/fixtures/simple_quote.txt +1 -0
- data/spec/support/fixtures/simple_quote_output.html +3 -0
- data/spec/support/fixtures/timeline_event.txt +1 -0
- data/spec/support/fixtures/timeline_event_output.html +15 -0
- data/spec/support/fixtures/timeline_info.txt +1 -0
- data/spec/support/fixtures/timeline_info_output.html +14 -0
- data/spec/support/fixtures/timeline_person.txt +4 -0
- data/spec/support/fixtures/timeline_person_output.html +23 -0
- data/spec/support/templates/erb/quote.html.erb +12 -0
- data/spec/support/templates/haml/collapsible_list.html.haml +2 -0
- data/spec/support/templates/haml/item.html.haml +3 -0
- data/spec/support/templates/haml/quote.html.haml +8 -0
- data/spec/support/templates/haml/timeline_event.html.haml +10 -0
- data/spec/support/templates/haml/timeline_info.html.haml +8 -0
- data/spec/support/templates/haml/timeline_person.html.haml +15 -0
- data/spec/tag_spec.rb +31 -0
- data/spec/transformer_spec.rb +118 -0
- metadata +211 -0
data/.gitignore
ADDED
data/.rbenv-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3-p392
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Jamie Dyer
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Shortcode
|
2
|
+
|
3
|
+
A ruby gem for parsing Wordpress style shortcodes. The gem uses a PEG (Parsing Expression Grammar) parser rather than using regular expressions so its easier to understand, test and extend.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'shortcode'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install shortcode
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Example usage
|
22
|
+
|
23
|
+
parser = Shortcode::Parser.new
|
24
|
+
transformer = Shortcode::Transformer.new
|
25
|
+
transformer.apply(parser.parse("[quote]Hello World[/quote]"))
|
26
|
+
|
27
|
+
Configuration
|
28
|
+
|
29
|
+
Shortcode.setup do |config|
|
30
|
+
|
31
|
+
# the template parser to use
|
32
|
+
config.template_parser = :haml # :erb or :haml supported, :haml is default
|
33
|
+
|
34
|
+
# location of the template files
|
35
|
+
config.template_path = "support/templates/haml"
|
36
|
+
|
37
|
+
# a list of block tags to support e.g. [quote]Hello World[/quote]
|
38
|
+
config.block_tags = [:quote, :collapsible_list, :item, :timeline_person]
|
39
|
+
|
40
|
+
# a list of self closing tags to support e.g. [gallery]
|
41
|
+
config.self_closing_tags = [:timeline_event, :timeline_info]
|
42
|
+
end
|
43
|
+
|
44
|
+
## Contributing
|
45
|
+
|
46
|
+
1. Fork it
|
47
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
48
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
49
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
50
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/shortcode.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
require 'haml'
|
3
|
+
require 'erb'
|
4
|
+
require 'facets/module/mattr'
|
5
|
+
|
6
|
+
module Shortcode
|
7
|
+
|
8
|
+
# Sets the template parser to use, supports :erb and :haml, default is :haml
|
9
|
+
mattr_accessor :template_parser
|
10
|
+
@@template_parser = :haml
|
11
|
+
|
12
|
+
# Sets the template parser to use, supports :erb and :haml, default is :haml
|
13
|
+
mattr_accessor :template_path
|
14
|
+
@@template_path = "app/views/shortcode_templates"
|
15
|
+
|
16
|
+
# Set the supported block_tags
|
17
|
+
mattr_accessor :block_tags
|
18
|
+
@@block_tags = [:quote, :collapsible_list, :item, :timeline_person]
|
19
|
+
|
20
|
+
# Set the supported self_closing_tags
|
21
|
+
mattr_accessor :self_closing_tags
|
22
|
+
@@self_closing_tags = [:timeline_event, :timeline_info]
|
23
|
+
|
24
|
+
def self.setup
|
25
|
+
yield self
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
require 'shortcode/version'
|
31
|
+
require 'shortcode/parser'
|
32
|
+
require 'shortcode/transformer'
|
33
|
+
require 'shortcode/tag'
|
34
|
+
require 'shortcode/exceptions'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Shortcode::Parser < Parslet::Parser
|
2
|
+
|
3
|
+
rule(:block_tag) { match_any_of Shortcode.block_tags }
|
4
|
+
rule(:self_closing_tag) { match_any_of Shortcode.self_closing_tags }
|
5
|
+
|
6
|
+
rule(:quotes) { str('"') }
|
7
|
+
|
8
|
+
rule(:space) { str(' ').repeat(1) }
|
9
|
+
rule(:space?) { space.maybe }
|
10
|
+
rule(:newline) { (str("\r\n") | str("\n")) >> space? }
|
11
|
+
rule(:whitespace) { (space | newline).repeat(1) }
|
12
|
+
rule(:whitespace?) { whitespace.maybe }
|
13
|
+
|
14
|
+
rule(:key) { match('[a-zA-Z0-9\-_]').repeat(1) }
|
15
|
+
rule(:value) { quotes >> (quotes.absent? >> any).repeat.as(:value) >> quotes }
|
16
|
+
|
17
|
+
rule(:option) { key.as(:key) >> str('=') >> value }
|
18
|
+
rule(:options) { (str(' ') >> option).repeat(1) }
|
19
|
+
rule(:options?) { options.repeat(0, 1) }
|
20
|
+
|
21
|
+
rule(:open) { str('[') >> block_tag.as(:open) >> options?.as(:options) >> str(']') >> whitespace? }
|
22
|
+
rule(:close) { str('[/') >> block_tag.as(:close) >> str(']') >> whitespace? }
|
23
|
+
rule(:open_close) { str('[') >> self_closing_tag.as(:open_close) >> options?.as(:options) >> str(']') >> whitespace? }
|
24
|
+
|
25
|
+
rule(:text) { ((close | block | open_close).absent? >> any).repeat(1).as(:text) }
|
26
|
+
rule(:block) { (open >> (block | text | open_close).repeat.as(:inner) >> close) }
|
27
|
+
|
28
|
+
rule(:body) { (block | text | open_close).repeat.as(:body) }
|
29
|
+
root(:body)
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def match_any_of(tags)
|
34
|
+
tags.map{ |tag| str(tag) }.inject do |tag_chain, tag|
|
35
|
+
tag_chain.send :|, tag
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Shortcode::Tag
|
2
|
+
|
3
|
+
def initialize(name, opts=[])
|
4
|
+
@name = name.downcase
|
5
|
+
set_options opts
|
6
|
+
end
|
7
|
+
|
8
|
+
def set_options(opts)
|
9
|
+
hash = {}
|
10
|
+
opts.each { |o| hash[o[:key].to_sym] = o[:value] }
|
11
|
+
@options = hash
|
12
|
+
end
|
13
|
+
|
14
|
+
def markup
|
15
|
+
template_files.each do |path|
|
16
|
+
return File.read(path) if File.file? path
|
17
|
+
end
|
18
|
+
raise Shortcode::TemplateNotFound, "Searched in:", template_files
|
19
|
+
end
|
20
|
+
|
21
|
+
def wrap(text='')
|
22
|
+
@text = text
|
23
|
+
render_template
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def render_template
|
29
|
+
case Shortcode.template_parser
|
30
|
+
when :haml
|
31
|
+
Haml::Engine.new(markup, ugly: true).render(binding)
|
32
|
+
when :erb
|
33
|
+
ERB.new(markup).result(binding)
|
34
|
+
else
|
35
|
+
raise Shortcode::TemplateParserNotSupported, Shortcode.template_parser
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def template_files
|
40
|
+
template_paths.map do |filename|
|
41
|
+
File.join Shortcode.template_path, filename
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def template_paths
|
46
|
+
[ "#{@name}.html.#{Shortcode.template_parser.to_s}", "#{@name}.#{Shortcode.template_parser.to_s}" ]
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Shortcode::Transformer < Parslet::Transform
|
2
|
+
|
3
|
+
rule(text: simple(:text)) { String(text) }
|
4
|
+
rule(
|
5
|
+
open: simple(:name),
|
6
|
+
options: subtree(:options),
|
7
|
+
inner: sequence(:inner),
|
8
|
+
close: simple(:name)
|
9
|
+
) { Shortcode::Tag.new(name.to_s, options).wrap(inner.join) }
|
10
|
+
rule(
|
11
|
+
open_close: simple(:name),
|
12
|
+
options: subtree(:options)
|
13
|
+
) { Shortcode::Tag.new(name.to_s, options).wrap }
|
14
|
+
|
15
|
+
rule(body: sequence(:strings)) { strings.join }
|
16
|
+
end
|
data/shortcode.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'shortcode/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "shortcode"
|
8
|
+
spec.version = Shortcode::VERSION
|
9
|
+
spec.authors = ["Jamie Dyer"]
|
10
|
+
spec.email = ["jamie@kernowsoul.com"]
|
11
|
+
spec.description = "Gem for parsing wordpress style shortcodes"
|
12
|
+
spec.summary = "Gem for parsing wordpress style shortcodes"
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "parslet", "1.5.0"
|
22
|
+
spec.add_dependency "haml", "4.0.0"
|
23
|
+
spec.add_dependency "facets", "2.9.3"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
|
+
end
|
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,235 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'parslet/rig/rspec'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
describe Shortcode::Parser do
|
6
|
+
|
7
|
+
let(:parser) { Shortcode::Parser.new }
|
8
|
+
|
9
|
+
let(:simple_quote) { load_fixture :simple_quote }
|
10
|
+
let(:full_quote) { load_fixture :full_quote }
|
11
|
+
let(:quote_with_extras) { load_fixture :quote_with_extras }
|
12
|
+
let(:simple_list) { load_fixture :simple_list }
|
13
|
+
let(:timeline_event) { load_fixture :timeline_event }
|
14
|
+
let(:timeline_info) { load_fixture :timeline_info }
|
15
|
+
let(:timeline_person) { load_fixture :timeline_person }
|
16
|
+
let(:complex_snippet) { load_fixture :complex_snippet }
|
17
|
+
|
18
|
+
let(:quotes) { [simple_quote, full_quote, quote_with_extras] }
|
19
|
+
let(:collapsible_lists) { [simple_list] }
|
20
|
+
let(:timelines) { [timeline_event, timeline_info, timeline_person] }
|
21
|
+
|
22
|
+
it "parses quote shortcodes" do
|
23
|
+
quotes.each do |string|
|
24
|
+
parser.should parse(string)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "parses list shortcodes" do
|
29
|
+
collapsible_lists.each do |string|
|
30
|
+
parser.should parse(string)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "parses timeline shortcodes" do
|
35
|
+
timelines.each do |string|
|
36
|
+
parser.should parse(string)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "parses complex nested shortcodes" do
|
41
|
+
parser.should parse(complex_snippet)
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "parsed strings" do
|
45
|
+
|
46
|
+
context "simple_quote" do
|
47
|
+
|
48
|
+
let(:parsed_object) { parser.parse(simple_quote) }
|
49
|
+
|
50
|
+
it "created the expected object" do
|
51
|
+
parsed_object[:body].should == [{ open: "quote", options: [], inner: [{ text: "hello" }], close: "quote" }]
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
context "full_quote" do
|
57
|
+
|
58
|
+
let(:parsed_object) { parser.parse(full_quote) }
|
59
|
+
|
60
|
+
it "created the expected object" do
|
61
|
+
parsed_object[:body].should == [{
|
62
|
+
open: "quote",
|
63
|
+
options: [
|
64
|
+
{ key: "author", value: "Jamie Dyer" },
|
65
|
+
{ key: "title", value: "King of England" }
|
66
|
+
],
|
67
|
+
inner: [{ text: "A quote" }],
|
68
|
+
close: "quote"
|
69
|
+
}]
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
context "quote_with_extras" do
|
75
|
+
|
76
|
+
let(:parsed_object) { parser.parse(quote_with_extras) }
|
77
|
+
|
78
|
+
it "created the expected object" do
|
79
|
+
parsed_object[:body].should == [
|
80
|
+
{ text: "Blah blah " },
|
81
|
+
{
|
82
|
+
open: "quote",
|
83
|
+
options: [
|
84
|
+
{ key: "author", value: "Jamie Dyer" }
|
85
|
+
],
|
86
|
+
inner: [{ text: "A quote" }],
|
87
|
+
close: "quote"
|
88
|
+
},
|
89
|
+
{ text: "<br> blah blah\n" }
|
90
|
+
]
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
context "simple_list" do
|
96
|
+
|
97
|
+
let(:parsed_object) { parser.parse(simple_list) }
|
98
|
+
|
99
|
+
it "created the expected object" do
|
100
|
+
parsed_object[:body].should == [{
|
101
|
+
open: "collapsible_list",
|
102
|
+
options: [],
|
103
|
+
inner: [{
|
104
|
+
open: "item",
|
105
|
+
options: [{ key: "title", value: "Example title 1" }],
|
106
|
+
inner: [{ text: "Example content 1" }],
|
107
|
+
close: "item"
|
108
|
+
},
|
109
|
+
{
|
110
|
+
open: "item",
|
111
|
+
options: [{ key: "title", value: "Example title 2" }],
|
112
|
+
inner: [{ text: "Example content 2" }],
|
113
|
+
close: "item"
|
114
|
+
},
|
115
|
+
{
|
116
|
+
open: "item",
|
117
|
+
options: [{ key: "title", value: "Example title 3" }],
|
118
|
+
inner: [{ text: "Example content 3" }],
|
119
|
+
close: "item"
|
120
|
+
}],
|
121
|
+
close: "collapsible_list"
|
122
|
+
}]
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
context "timeline_event" do
|
128
|
+
|
129
|
+
let(:parsed_object) { parser.parse(timeline_event) }
|
130
|
+
|
131
|
+
it "created the expected object" do
|
132
|
+
parsed_object[:body].should == [{
|
133
|
+
open_close: "timeline_event",
|
134
|
+
options: [
|
135
|
+
{ key: "date", value: "March 2013" },
|
136
|
+
{ key: "title", value: "a title" },
|
137
|
+
{ key: "link", value: "http://blah.com" }
|
138
|
+
]
|
139
|
+
}]
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
context "timeline_info" do
|
145
|
+
|
146
|
+
let(:parsed_object) { parser.parse(timeline_info) }
|
147
|
+
|
148
|
+
it "created the expected object" do
|
149
|
+
parsed_object[:body].should == [{
|
150
|
+
open_close: "timeline_info",
|
151
|
+
options: [
|
152
|
+
{ key: "date", value: "Feb 2013" },
|
153
|
+
{ key: "title", value: "Something amazing" }
|
154
|
+
]
|
155
|
+
}]
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
context "timeline_person" do
|
161
|
+
|
162
|
+
let(:parsed_object) { parser.parse(timeline_person) }
|
163
|
+
|
164
|
+
it "created the expected object" do
|
165
|
+
parsed_object[:body].should == [{
|
166
|
+
open: "timeline_person",
|
167
|
+
options: [
|
168
|
+
{ key: "date", value: "Jan 2012" },
|
169
|
+
{ key: "title", value: "A real title" },
|
170
|
+
{ key: "image", value: "/images/person.jpg" },
|
171
|
+
{ key: "name", value: "Sam Smith" },
|
172
|
+
{ key: "position", value: "Presedent" },
|
173
|
+
{ key: "link", value: "http://blah.com" }
|
174
|
+
],
|
175
|
+
inner: [{ text: "A bit of body copy\nwith a newline\n" }],
|
176
|
+
close: "timeline_person"
|
177
|
+
}]
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
context "complex_snippet" do
|
183
|
+
|
184
|
+
let(:parsed_object) { parser.parse(complex_snippet) }
|
185
|
+
|
186
|
+
it "created the expected object" do
|
187
|
+
parsed_object[:body].should == [{
|
188
|
+
text: "<h3>A page title</h3>\n<p>Some text</p>\n"},
|
189
|
+
{
|
190
|
+
open: "collapsible_list",
|
191
|
+
options: [],
|
192
|
+
inner: [{
|
193
|
+
open: "item",
|
194
|
+
options: [{ key: "title", value: "Example title 1" }],
|
195
|
+
inner: [{
|
196
|
+
open: "quote",
|
197
|
+
options: [
|
198
|
+
{ key: "author", value: "Jamie Dyer" },
|
199
|
+
{ key: "title", value: "King of England" }
|
200
|
+
],
|
201
|
+
inner: [{ text: "A quote" }],
|
202
|
+
close: "quote"
|
203
|
+
},
|
204
|
+
{ text: "I'm inbetween 2 quotes!\n " },
|
205
|
+
{
|
206
|
+
open: "quote",
|
207
|
+
options: [
|
208
|
+
{ key: "author", value: "Forrest Gump" },
|
209
|
+
{ key: "title", value: "Idiot" }
|
210
|
+
],
|
211
|
+
inner: [{text: "Life is like..."}],
|
212
|
+
close: "quote"
|
213
|
+
}],
|
214
|
+
close: "item"
|
215
|
+
},
|
216
|
+
{
|
217
|
+
open: "item",
|
218
|
+
options: [{ key: "title", value: "Example title 2" }],
|
219
|
+
inner: [{ text: "Example content 2" }],
|
220
|
+
close: "item"
|
221
|
+
},
|
222
|
+
{
|
223
|
+
open: "item",
|
224
|
+
options: [{ key: "title", value: "Example title 3" }],
|
225
|
+
inner: [{ text: "Example content 3" }],
|
226
|
+
close: "item"
|
227
|
+
}],
|
228
|
+
close: "collapsible_list"
|
229
|
+
},
|
230
|
+
{ text: "<p>Some more text</p>\n" }
|
231
|
+
]
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
require 'rspec'
|
3
|
+
require 'shortcode'
|
4
|
+
require 'support/fixtures'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.order = "random"
|
8
|
+
|
9
|
+
config.before(:each) do
|
10
|
+
Shortcode.setup do |config|
|
11
|
+
config.template_parser = :haml
|
12
|
+
config.template_path = File.join File.dirname(__FILE__), "support/templates/haml"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<h3>A page title</h3>
|
2
|
+
<p>Some text</p>
|
3
|
+
[collapsible_list]
|
4
|
+
[item title="Example title 1"]
|
5
|
+
[quote author="Jamie Dyer" title="King of England"]A quote[/quote]
|
6
|
+
I'm inbetween 2 quotes!
|
7
|
+
[quote author="Forrest Gump" title="Idiot"]Life is like...[/quote]
|
8
|
+
[/item]
|
9
|
+
[item title="Example title 2"]Example content 2[/item]
|
10
|
+
[item title="Example title 3"]Example content 3[/item]
|
11
|
+
[/collapsible_list]
|
12
|
+
|
13
|
+
<p>Some more text</p>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<h3>A page title</h3>
|
2
|
+
<p>Some text</p>
|
3
|
+
<div class='collapsible'>
|
4
|
+
<section>
|
5
|
+
<h5>Example title 1</h5>
|
6
|
+
<div><blockquote>
|
7
|
+
<p class='quotation'>A quote</p>
|
8
|
+
<p class='citation'>
|
9
|
+
<span class='author'>Jamie Dyer</span>
|
10
|
+
<span class='position'>King of England</span>
|
11
|
+
</p>
|
12
|
+
</blockquote>
|
13
|
+
I'm inbetween 2 quotes!
|
14
|
+
<blockquote>
|
15
|
+
<p class='quotation'>Life is like...</p>
|
16
|
+
<p class='citation'>
|
17
|
+
<span class='author'>Forrest Gump</span>
|
18
|
+
<span class='position'>Idiot</span>
|
19
|
+
</p>
|
20
|
+
</blockquote>
|
21
|
+
</div>
|
22
|
+
</section>
|
23
|
+
<section>
|
24
|
+
<h5>Example title 2</h5>
|
25
|
+
<div>Example content 2</div>
|
26
|
+
</section>
|
27
|
+
<section>
|
28
|
+
<h5>Example title 3</h5>
|
29
|
+
<div>Example content 3</div>
|
30
|
+
</section>
|
31
|
+
|
32
|
+
</div>
|
33
|
+
<p>Some more text</p>
|
@@ -0,0 +1 @@
|
|
1
|
+
[quote author="Jamie Dyer" title="King of England"]A quote[/quote]
|
@@ -0,0 +1 @@
|
|
1
|
+
Blah blah [quote author="Jamie Dyer"]A quote[/quote] <br> blah blah
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<div class='collapsible'>
|
2
|
+
<section>
|
3
|
+
<h5>Example title 1</h5>
|
4
|
+
<div>Example content 1</div>
|
5
|
+
</section>
|
6
|
+
<section>
|
7
|
+
<h5>Example title 2</h5>
|
8
|
+
<div>Example content 2</div>
|
9
|
+
</section>
|
10
|
+
<section>
|
11
|
+
<h5>Example title 3</h5>
|
12
|
+
<div>Example content 3</div>
|
13
|
+
</section>
|
14
|
+
|
15
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
[quote]hello[/quote]
|
@@ -0,0 +1 @@
|
|
1
|
+
[timeline_event date="March 2013" title="a title" link="http://blah.com"]
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<div class='timeline'>
|
2
|
+
<table>
|
3
|
+
<tbody>
|
4
|
+
<tr>
|
5
|
+
<th scope='row'>
|
6
|
+
March 2013
|
7
|
+
</th>
|
8
|
+
<td class='event'>
|
9
|
+
<span class='description'>a title</span>
|
10
|
+
<a class='read_more' href='http://blah.com'>Read More</a>
|
11
|
+
</td>
|
12
|
+
</tr>
|
13
|
+
</tbody>
|
14
|
+
</table>
|
15
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
[timeline_info date="Feb 2013" title="Something amazing"]
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<div class='timeline'>
|
2
|
+
<table>
|
3
|
+
<tbody>
|
4
|
+
<tr>
|
5
|
+
<th scope='row'>
|
6
|
+
Jan 2012
|
7
|
+
</th>
|
8
|
+
<td class='team_news'>
|
9
|
+
<img src='/images/person.jpg'>
|
10
|
+
<h4>A real title</h4>
|
11
|
+
<span class='name'>Sam Smith</span>
|
12
|
+
<span class='position'>Presedent</span>
|
13
|
+
<a class='read_more' href='http://blah.com'>View Profile</a>
|
14
|
+
<div class='description'>
|
15
|
+
<p>A bit of body copy
|
16
|
+
with a newline
|
17
|
+
</p>
|
18
|
+
</div>
|
19
|
+
</td>
|
20
|
+
</tr>
|
21
|
+
</tbody>
|
22
|
+
</table>
|
23
|
+
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<blockquote>
|
2
|
+
<p class='quotation'><%= @text %></p>
|
3
|
+
<% if @options[:author] || @options[:title] %>
|
4
|
+
<p class='citation'>
|
5
|
+
<% if @options[:author] %>
|
6
|
+
<span class='author'><%= @options[:author] %></span>
|
7
|
+
<% end %>
|
8
|
+
<% if @options[:title] <% end %><span class='position'><%= @options[:title] %></span>
|
9
|
+
<% end %>
|
10
|
+
</p>
|
11
|
+
<% end %>
|
12
|
+
</blockquote>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
.timeline
|
2
|
+
%table
|
3
|
+
%tbody
|
4
|
+
%tr
|
5
|
+
%th{scope: :row}
|
6
|
+
= @options[:date]
|
7
|
+
%td.team_news
|
8
|
+
%img{src: @options[:image]}
|
9
|
+
%h4= @options[:title]
|
10
|
+
%span.name= @options[:name]
|
11
|
+
%span.position= @options[:position]
|
12
|
+
-if @options[:link]
|
13
|
+
%a.read_more{href: @options[:link]} View Profile
|
14
|
+
.description
|
15
|
+
%p= @text
|
data/spec/tag_spec.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shortcode::Tag do
|
4
|
+
|
5
|
+
context "when the template file is missing" do
|
6
|
+
|
7
|
+
let(:tag) { Shortcode::Tag.new('doesnt_exist') }
|
8
|
+
|
9
|
+
it "raises a TemplateNotFound error when the file doesn't exists" do
|
10
|
+
expect { tag.wrap }.to raise_error(Shortcode::TemplateNotFound)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when an unsupported template parser is specified" do
|
16
|
+
|
17
|
+
let(:tag) { Shortcode::Tag.new('quote') }
|
18
|
+
|
19
|
+
before(:each) do
|
20
|
+
Shortcode.setup do |config|
|
21
|
+
config.template_parser = :something_crazy
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "raises a TemplateNotFound error when the file doesn't exists" do
|
26
|
+
expect { tag.wrap }.to raise_error(Shortcode::TemplateParserNotSupported)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'parslet/rig/rspec'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
describe Shortcode do
|
6
|
+
|
7
|
+
let(:parser) { Shortcode::Parser.new }
|
8
|
+
let(:transformer) { Shortcode::Transformer.new }
|
9
|
+
|
10
|
+
let(:simple_quote) { load_fixture :simple_quote }
|
11
|
+
let(:full_quote) { load_fixture :full_quote }
|
12
|
+
let(:quote_with_extras) { load_fixture :quote_with_extras }
|
13
|
+
let(:simple_list) { load_fixture :simple_list }
|
14
|
+
let(:timeline_event) { load_fixture :timeline_event }
|
15
|
+
let(:timeline_info) { load_fixture :timeline_info }
|
16
|
+
let(:timeline_person) { load_fixture :timeline_person }
|
17
|
+
let(:complex_snippet) { load_fixture :complex_snippet }
|
18
|
+
|
19
|
+
let(:quotes) { [simple_quote, full_quote, quote_with_extras] }
|
20
|
+
let(:collapsible_lists) { [simple_list] }
|
21
|
+
let(:timelines) { [timeline_event, timeline_info, timeline_person] }
|
22
|
+
|
23
|
+
let(:simple_quote_output) { load_fixture :simple_quote_output, :html }
|
24
|
+
let(:full_quote_output) { load_fixture :full_quote_output, :html }
|
25
|
+
let(:quote_with_extras_output) { load_fixture :quote_with_extras_output, :html }
|
26
|
+
let(:simple_list_output) { load_fixture :simple_list_output, :html }
|
27
|
+
let(:timeline_event_output) { load_fixture :timeline_event_output, :html }
|
28
|
+
let(:timeline_info_output) { load_fixture :timeline_info_output, :html }
|
29
|
+
let(:timeline_person_output) { load_fixture :timeline_person_output, :html }
|
30
|
+
let(:complex_snippet_output) { load_fixture :complex_snippet_output, :html }
|
31
|
+
|
32
|
+
context "simple_quote" do
|
33
|
+
|
34
|
+
it "converts into html" do
|
35
|
+
obj = parser.parse(simple_quote)
|
36
|
+
html = transformer.apply obj
|
37
|
+
html.should == simple_quote_output
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
context "full_quote" do
|
43
|
+
|
44
|
+
it "converts into html" do
|
45
|
+
html = transformer.apply(parser.parse(full_quote))
|
46
|
+
html.should == full_quote_output
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
context "quote_with_extras" do
|
52
|
+
|
53
|
+
it "converts into html" do
|
54
|
+
html = transformer.apply(parser.parse(quote_with_extras))
|
55
|
+
html.should == quote_with_extras_output
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
context "simple_list" do
|
61
|
+
|
62
|
+
it "converts into html" do
|
63
|
+
html = transformer.apply(parser.parse(simple_list))
|
64
|
+
html.should == simple_list_output
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
context "timeline_event" do
|
70
|
+
|
71
|
+
it "converts into html" do
|
72
|
+
html = transformer.apply(parser.parse(timeline_event))
|
73
|
+
html.should == timeline_event_output
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
context "timeline_info" do
|
79
|
+
|
80
|
+
it "converts into html" do
|
81
|
+
html = transformer.apply(parser.parse(timeline_info))
|
82
|
+
html.should == timeline_info_output
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
context "timeline_person" do
|
88
|
+
|
89
|
+
it "converts into html" do
|
90
|
+
html = transformer.apply(parser.parse(timeline_person))
|
91
|
+
html.should == timeline_person_output
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
context "complex_snippet" do
|
97
|
+
|
98
|
+
it "converts into html" do
|
99
|
+
html = transformer.apply(parser.parse(complex_snippet))
|
100
|
+
html.should == complex_snippet_output
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context "erb templates" do
|
105
|
+
|
106
|
+
before(:each) do
|
107
|
+
Shortcode.setup do |config|
|
108
|
+
config.template_parser = :erb
|
109
|
+
config.template_path = File.join File.dirname(__FILE__), "support/templates/erb"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
it "converts into html" do
|
114
|
+
html = transformer.apply(parser.parse(simple_quote))
|
115
|
+
html.gsub("\n",'').should == simple_quote_output.gsub("\n",'')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
metadata
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: shortcode
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jamie Dyer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-08-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: parslet
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.5.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.5.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: haml
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - '='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 4.0.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - '='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 4.0.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: facets
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - '='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.9.3
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.9.3
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: bundler
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.3'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.3'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: Gem for parsing wordpress style shortcodes
|
111
|
+
email:
|
112
|
+
- jamie@kernowsoul.com
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- .gitignore
|
118
|
+
- .rbenv-version
|
119
|
+
- Gemfile
|
120
|
+
- LICENSE.txt
|
121
|
+
- README.md
|
122
|
+
- Rakefile
|
123
|
+
- lib/shortcode.rb
|
124
|
+
- lib/shortcode/exceptions.rb
|
125
|
+
- lib/shortcode/parser.rb
|
126
|
+
- lib/shortcode/tag.rb
|
127
|
+
- lib/shortcode/transformer.rb
|
128
|
+
- lib/shortcode/version.rb
|
129
|
+
- shortcode.gemspec
|
130
|
+
- spec/parser_spec.rb
|
131
|
+
- spec/spec_helper.rb
|
132
|
+
- spec/support/fixtures.rb
|
133
|
+
- spec/support/fixtures/complex_snippet.txt
|
134
|
+
- spec/support/fixtures/complex_snippet_output.html
|
135
|
+
- spec/support/fixtures/full_quote.txt
|
136
|
+
- spec/support/fixtures/full_quote_output.html
|
137
|
+
- spec/support/fixtures/quote_with_extras.txt
|
138
|
+
- spec/support/fixtures/quote_with_extras_output.html
|
139
|
+
- spec/support/fixtures/simple_list.txt
|
140
|
+
- spec/support/fixtures/simple_list_output.html
|
141
|
+
- spec/support/fixtures/simple_quote.txt
|
142
|
+
- spec/support/fixtures/simple_quote_output.html
|
143
|
+
- spec/support/fixtures/timeline_event.txt
|
144
|
+
- spec/support/fixtures/timeline_event_output.html
|
145
|
+
- spec/support/fixtures/timeline_info.txt
|
146
|
+
- spec/support/fixtures/timeline_info_output.html
|
147
|
+
- spec/support/fixtures/timeline_person.txt
|
148
|
+
- spec/support/fixtures/timeline_person_output.html
|
149
|
+
- spec/support/templates/erb/quote.html.erb
|
150
|
+
- spec/support/templates/haml/collapsible_list.html.haml
|
151
|
+
- spec/support/templates/haml/item.html.haml
|
152
|
+
- spec/support/templates/haml/quote.html.haml
|
153
|
+
- spec/support/templates/haml/timeline_event.html.haml
|
154
|
+
- spec/support/templates/haml/timeline_info.html.haml
|
155
|
+
- spec/support/templates/haml/timeline_person.html.haml
|
156
|
+
- spec/tag_spec.rb
|
157
|
+
- spec/transformer_spec.rb
|
158
|
+
homepage: ''
|
159
|
+
licenses:
|
160
|
+
- MIT
|
161
|
+
post_install_message:
|
162
|
+
rdoc_options: []
|
163
|
+
require_paths:
|
164
|
+
- lib
|
165
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
166
|
+
none: false
|
167
|
+
requirements:
|
168
|
+
- - ! '>='
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0'
|
171
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
|
+
none: false
|
173
|
+
requirements:
|
174
|
+
- - ! '>='
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
requirements: []
|
178
|
+
rubyforge_project:
|
179
|
+
rubygems_version: 1.8.23
|
180
|
+
signing_key:
|
181
|
+
specification_version: 3
|
182
|
+
summary: Gem for parsing wordpress style shortcodes
|
183
|
+
test_files:
|
184
|
+
- spec/parser_spec.rb
|
185
|
+
- spec/spec_helper.rb
|
186
|
+
- spec/support/fixtures.rb
|
187
|
+
- spec/support/fixtures/complex_snippet.txt
|
188
|
+
- spec/support/fixtures/complex_snippet_output.html
|
189
|
+
- spec/support/fixtures/full_quote.txt
|
190
|
+
- spec/support/fixtures/full_quote_output.html
|
191
|
+
- spec/support/fixtures/quote_with_extras.txt
|
192
|
+
- spec/support/fixtures/quote_with_extras_output.html
|
193
|
+
- spec/support/fixtures/simple_list.txt
|
194
|
+
- spec/support/fixtures/simple_list_output.html
|
195
|
+
- spec/support/fixtures/simple_quote.txt
|
196
|
+
- spec/support/fixtures/simple_quote_output.html
|
197
|
+
- spec/support/fixtures/timeline_event.txt
|
198
|
+
- spec/support/fixtures/timeline_event_output.html
|
199
|
+
- spec/support/fixtures/timeline_info.txt
|
200
|
+
- spec/support/fixtures/timeline_info_output.html
|
201
|
+
- spec/support/fixtures/timeline_person.txt
|
202
|
+
- spec/support/fixtures/timeline_person_output.html
|
203
|
+
- spec/support/templates/erb/quote.html.erb
|
204
|
+
- spec/support/templates/haml/collapsible_list.html.haml
|
205
|
+
- spec/support/templates/haml/item.html.haml
|
206
|
+
- spec/support/templates/haml/quote.html.haml
|
207
|
+
- spec/support/templates/haml/timeline_event.html.haml
|
208
|
+
- spec/support/templates/haml/timeline_info.html.haml
|
209
|
+
- spec/support/templates/haml/timeline_person.html.haml
|
210
|
+
- spec/tag_spec.rb
|
211
|
+
- spec/transformer_spec.rb
|