shortcode 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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