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.
Files changed (42) hide show
  1. data/.gitignore +18 -0
  2. data/.rbenv-version +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +50 -0
  6. data/Rakefile +1 -0
  7. data/lib/shortcode.rb +34 -0
  8. data/lib/shortcode/exceptions.rb +9 -0
  9. data/lib/shortcode/parser.rb +39 -0
  10. data/lib/shortcode/tag.rb +48 -0
  11. data/lib/shortcode/transformer.rb +16 -0
  12. data/lib/shortcode/version.rb +3 -0
  13. data/shortcode.gemspec +28 -0
  14. data/spec/parser_spec.rb +235 -0
  15. data/spec/spec_helper.rb +15 -0
  16. data/spec/support/fixtures.rb +7 -0
  17. data/spec/support/fixtures/complex_snippet.txt +13 -0
  18. data/spec/support/fixtures/complex_snippet_output.html +33 -0
  19. data/spec/support/fixtures/full_quote.txt +1 -0
  20. data/spec/support/fixtures/full_quote_output.html +7 -0
  21. data/spec/support/fixtures/quote_with_extras.txt +1 -0
  22. data/spec/support/fixtures/quote_with_extras_output.html +7 -0
  23. data/spec/support/fixtures/simple_list.txt +5 -0
  24. data/spec/support/fixtures/simple_list_output.html +15 -0
  25. data/spec/support/fixtures/simple_quote.txt +1 -0
  26. data/spec/support/fixtures/simple_quote_output.html +3 -0
  27. data/spec/support/fixtures/timeline_event.txt +1 -0
  28. data/spec/support/fixtures/timeline_event_output.html +15 -0
  29. data/spec/support/fixtures/timeline_info.txt +1 -0
  30. data/spec/support/fixtures/timeline_info_output.html +14 -0
  31. data/spec/support/fixtures/timeline_person.txt +4 -0
  32. data/spec/support/fixtures/timeline_person_output.html +23 -0
  33. data/spec/support/templates/erb/quote.html.erb +12 -0
  34. data/spec/support/templates/haml/collapsible_list.html.haml +2 -0
  35. data/spec/support/templates/haml/item.html.haml +3 -0
  36. data/spec/support/templates/haml/quote.html.haml +8 -0
  37. data/spec/support/templates/haml/timeline_event.html.haml +10 -0
  38. data/spec/support/templates/haml/timeline_info.html.haml +8 -0
  39. data/spec/support/templates/haml/timeline_person.html.haml +15 -0
  40. data/spec/tag_spec.rb +31 -0
  41. data/spec/transformer_spec.rb +118 -0
  42. metadata +211 -0
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
data/.rbenv-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p392
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in shortcode.gemspec
4
+ gemspec
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,9 @@
1
+ module Shortcode
2
+
3
+ # Raised when the template file can not be found
4
+ class TemplateNotFound < StandardError; end
5
+
6
+ # Raised when the template renderer specified is not supported
7
+ class TemplateParserNotSupported < StandardError; end
8
+
9
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module Shortcode
2
+ VERSION = "0.0.1"
3
+ 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
@@ -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
@@ -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,7 @@
1
+ RSpec.configure do |config|
2
+
3
+ def load_fixture(name, type='txt')
4
+ File.read File.join(File.dirname(__FILE__), 'fixtures', "#{name}.#{type}")
5
+ end
6
+
7
+ 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,7 @@
1
+ <blockquote>
2
+ <p class='quotation'>A quote</p>
3
+ <p class='citation'>
4
+ <span class='author'>Jamie Dyer</span>
5
+ <span class='position'>King of England</span>
6
+ </p>
7
+ </blockquote>
@@ -0,0 +1 @@
1
+ Blah blah [quote author="Jamie Dyer"]A quote[/quote] <br> blah blah
@@ -0,0 +1,7 @@
1
+ Blah blah <blockquote>
2
+ <p class='quotation'>A quote</p>
3
+ <p class='citation'>
4
+ <span class='author'>Jamie Dyer</span>
5
+ </p>
6
+ </blockquote>
7
+ <br> blah blah
@@ -0,0 +1,5 @@
1
+ [collapsible_list]
2
+ [item title="Example title 1"]Example content 1[/item]
3
+ [item title="Example title 2"]Example content 2[/item]
4
+ [item title="Example title 3"]Example content 3[/item]
5
+ [/collapsible_list]
@@ -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,3 @@
1
+ <blockquote>
2
+ <p class='quotation'>hello</p>
3
+ </blockquote>
@@ -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,14 @@
1
+ <div class='timeline'>
2
+ <table>
3
+ <tbody>
4
+ <tr>
5
+ <th scope='row'>
6
+ Feb 2013
7
+ </th>
8
+ <td class='information'>
9
+ <p>Something amazing</p>
10
+ </td>
11
+ </tr>
12
+ </tbody>
13
+ </table>
14
+ </div>
@@ -0,0 +1,4 @@
1
+ [timeline_person date="Jan 2012" title="A real title" image="/images/person.jpg" name="Sam Smith" position="Presedent" link="http://blah.com"]
2
+ A bit of body copy
3
+ with a newline
4
+ [/timeline_person]
@@ -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,2 @@
1
+ .collapsible
2
+ = @text
@@ -0,0 +1,3 @@
1
+ %section
2
+ %h5= @options[:title]
3
+ %div= @text
@@ -0,0 +1,8 @@
1
+ %blockquote
2
+ %p.quotation= @text
3
+ -if @options[:author] || @options[:title]
4
+ %p.citation
5
+ -if @options[:author]
6
+ %span.author= @options[:author]
7
+ -if @options[:title]
8
+ %span.position= @options[:title]
@@ -0,0 +1,10 @@
1
+ .timeline
2
+ %table
3
+ %tbody
4
+ %tr
5
+ %th{scope: :row}
6
+ = @options[:date]
7
+ %td.event
8
+ %span.description= @options[:title]
9
+ -if @options[:link]
10
+ %a.read_more{href: @options[:link]} Read More
@@ -0,0 +1,8 @@
1
+ .timeline
2
+ %table
3
+ %tbody
4
+ %tr
5
+ %th{scope: :row}
6
+ = @options[:date]
7
+ %td.information
8
+ %p= @options[:title]
@@ -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