flannel 0.2.1 → 0.2.3
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/VERSION.yml +2 -2
- data/features/fixtures/preformatted.flannel +2 -1
- data/features/fixtures/preformatted.out +2 -1
- data/flannel.gemspec +14 -14
- data/lib/flannel.rb +10 -1
- data/lib/flannel/block_cutter.rb +34 -0
- data/lib/flannel/cutting_board.rb +3 -7
- data/lib/flannel/feed_parser.rb +14 -10
- data/lib/flannel/html_formatter.rb +105 -0
- data/lib/flannel/text_block.rb +41 -0
- data/test/{shears_test.rb → block_cutter_test.rb} +7 -7
- data/test/cutting_board_test.rb +0 -5
- data/test/flannel_test.rb +6 -0
- data/test/html_formatter_test.rb +80 -0
- data/test/text_block_test.rb +64 -0
- metadata +11 -11
- data/lib/flannel/shears.rb +0 -89
- data/lib/flannel/square.rb +0 -92
- data/lib/flannel/stripe.rb +0 -77
- data/test/square_test.rb +0 -102
- data/test/stripe_test.rb +0 -126
data/VERSION.yml
CHANGED
data/flannel.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{flannel}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jamal Hansen"]
|
12
|
-
s.date = %q{2010-01-
|
12
|
+
s.date = %q{2010-01-25}
|
13
13
|
s.email = %q{jamal.hansen@gmail.com}
|
14
14
|
s.executables = ["quilt-it~", "quilt-it"]
|
15
15
|
s.extra_rdoc_files = [
|
@@ -50,22 +50,22 @@ Gem::Specification.new do |s|
|
|
50
50
|
"features/wiki_links.feature",
|
51
51
|
"flannel.gemspec",
|
52
52
|
"lib/flannel.rb",
|
53
|
+
"lib/flannel/block_cutter.rb",
|
53
54
|
"lib/flannel/cache_location_does_not_exist_error.rb",
|
54
55
|
"lib/flannel/cutting_board.rb",
|
55
56
|
"lib/flannel/feed_parser.rb",
|
56
57
|
"lib/flannel/file_cache.rb",
|
57
|
-
"lib/flannel/
|
58
|
-
"lib/flannel/
|
59
|
-
"lib/flannel/stripe.rb",
|
58
|
+
"lib/flannel/html_formatter.rb",
|
59
|
+
"lib/flannel/text_block.rb",
|
60
60
|
"lib/flannel/wrappable.rb",
|
61
|
+
"test/block_cutter_test.rb",
|
61
62
|
"test/cutting_board_test.rb",
|
62
63
|
"test/feed_parser_test.rb",
|
63
64
|
"test/file_cache_test.rb",
|
64
65
|
"test/flannel_test.rb",
|
65
|
-
"test/
|
66
|
-
"test/
|
67
|
-
"test/
|
68
|
-
"test/test_helper.rb"
|
66
|
+
"test/html_formatter_test.rb",
|
67
|
+
"test/test_helper.rb",
|
68
|
+
"test/text_block_test.rb"
|
69
69
|
]
|
70
70
|
s.homepage = %q{http://github.com/rubyyot/flannel}
|
71
71
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -74,14 +74,14 @@ Gem::Specification.new do |s|
|
|
74
74
|
s.rubygems_version = %q{1.3.5}
|
75
75
|
s.summary = %q{A soft comfortable worn in markup language for Ruby}
|
76
76
|
s.test_files = [
|
77
|
-
"test/
|
77
|
+
"test/html_formatter_test.rb",
|
78
|
+
"test/block_cutter_test.rb",
|
79
|
+
"test/test_helper.rb",
|
78
80
|
"test/file_cache_test.rb",
|
79
|
-
"test/stripe_test.rb",
|
80
81
|
"test/cutting_board_test.rb",
|
82
|
+
"test/text_block_test.rb",
|
81
83
|
"test/feed_parser_test.rb",
|
82
|
-
"test/flannel_test.rb"
|
83
|
-
"test/square_test.rb",
|
84
|
-
"test/shears_test.rb"
|
84
|
+
"test/flannel_test.rb"
|
85
85
|
]
|
86
86
|
|
87
87
|
if s.respond_to? :specification_version then
|
data/lib/flannel.rb
CHANGED
@@ -6,10 +6,19 @@ require 'flannel/stripe'
|
|
6
6
|
require 'flannel/feed_parser'
|
7
7
|
require 'flannel/file_cache'
|
8
8
|
|
9
|
+
require 'flannel/block_cutter'
|
10
|
+
require 'flannel/text_block'
|
11
|
+
require 'flannel/html_formatter'
|
12
|
+
|
9
13
|
module Flannel
|
10
14
|
def self.quilt markup, params={}
|
15
|
+
@@cache_params = params
|
11
16
|
return nil unless markup
|
12
|
-
shears = Flannel::CuttingBoard.new
|
17
|
+
shears = Flannel::CuttingBoard.new
|
13
18
|
shears.cut markup
|
14
19
|
end
|
20
|
+
|
21
|
+
def self.cache_params
|
22
|
+
@@cache_params
|
23
|
+
end
|
15
24
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Flannel
|
2
|
+
class BlockCutter
|
3
|
+
def cut markup
|
4
|
+
pieces = split_preformatted_blocks(markup)
|
5
|
+
pieces = pieces.map { |part| split_into_blocks(part) }
|
6
|
+
pieces.flatten!
|
7
|
+
convert_to_text_blocks pieces
|
8
|
+
end
|
9
|
+
|
10
|
+
def split_into_blocks markup
|
11
|
+
if is_preformatted markup
|
12
|
+
markup
|
13
|
+
else
|
14
|
+
markup.split(/\n\s*?\n/).map { |s| s.strip }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def split_preformatted_blocks markup
|
19
|
+
markup.split(/^(_(?=\n\n)|(?=_))/).map { |s| s.strip }.reject { |s| is_invalid_block s}
|
20
|
+
end
|
21
|
+
|
22
|
+
def convert_to_text_blocks pieces
|
23
|
+
pieces.map{ |piece| Flannel::TextBlock.new piece }
|
24
|
+
end
|
25
|
+
|
26
|
+
def is_invalid_block s
|
27
|
+
s == "" || s == "_"
|
28
|
+
end
|
29
|
+
|
30
|
+
def is_preformatted markup
|
31
|
+
markup[0] == '_'[0]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,14 +1,10 @@
|
|
1
1
|
|
2
2
|
module Flannel
|
3
3
|
class CuttingBoard
|
4
|
-
def initialize params={}
|
5
|
-
@params = params
|
6
|
-
end
|
7
|
-
|
8
4
|
def cut markup
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
cutter = Flannel::BlockCutter.new
|
6
|
+
text_blocks = cutter.cut markup
|
7
|
+
text_blocks.map { |text| text.to_h }.join("\n\n")
|
12
8
|
end
|
13
9
|
end
|
14
10
|
end
|
data/lib/flannel/feed_parser.rb
CHANGED
@@ -19,9 +19,7 @@ module Flannel
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def get_document url
|
22
|
-
doc =
|
23
|
-
doc = open(url) unless doc
|
24
|
-
@cache.save url, doc if @cache
|
22
|
+
doc = open(url)
|
25
23
|
doc
|
26
24
|
end
|
27
25
|
|
@@ -30,14 +28,20 @@ module Flannel
|
|
30
28
|
end
|
31
29
|
|
32
30
|
def get_news url
|
33
|
-
item_string =
|
34
|
-
|
35
|
-
|
31
|
+
item_string = nil
|
32
|
+
item_string = @cache.retrieve(url) if @cache
|
33
|
+
|
34
|
+
unless item_string
|
35
|
+
item_string = ""
|
36
|
+
doc = Hpricot.XML(get_document(url))
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
(doc/"item").each do |item|
|
39
|
+
link = (item/"link").inner_html
|
40
|
+
title = (item/"title").inner_html
|
41
|
+
item_string << format_item(link, title)
|
42
|
+
end
|
43
|
+
|
44
|
+
@cache.save url, item_string if @cache
|
41
45
|
end
|
42
46
|
|
43
47
|
item_string
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Flannel
|
2
|
+
class HtmlFormatter
|
3
|
+
include Wrappable
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@tags ={:preformatted => "pre", :feed => "ul", :list => "ul", :header_1 => "h1", :header_2 => "h2", :header_3 => "h3", :header_4 => "h4", :header_5 => "h5", :header_6 => "h6", :paragraph => "p"}
|
7
|
+
end
|
8
|
+
|
9
|
+
def do text, style
|
10
|
+
steps = get_steps_for style
|
11
|
+
inject text, steps
|
12
|
+
end
|
13
|
+
|
14
|
+
def permalink topic
|
15
|
+
topic.gsub(%r{[^/\w\s\-]},'').gsub(%r{[^\w/]|[\_]},' ').split.join('-').downcase
|
16
|
+
end
|
17
|
+
|
18
|
+
def inject text, steps
|
19
|
+
if steps.empty?
|
20
|
+
text
|
21
|
+
else
|
22
|
+
step = steps.shift
|
23
|
+
text = step.call text
|
24
|
+
inject text, steps
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_steps_for style
|
29
|
+
steps = []
|
30
|
+
|
31
|
+
case style
|
32
|
+
|
33
|
+
when :preformatted
|
34
|
+
steps << lambda { |text| html_escape text}
|
35
|
+
when :feed
|
36
|
+
steps << lambda { |text| parse_feed text }
|
37
|
+
else
|
38
|
+
steps << lambda { |text| build_wiki_links text }
|
39
|
+
steps << lambda { |text| convert_external_links text }
|
40
|
+
end
|
41
|
+
|
42
|
+
if style == :list
|
43
|
+
steps << lambda { |text| format_list text }
|
44
|
+
end
|
45
|
+
|
46
|
+
steps << lambda { |text| wrap text, @tags[style]}
|
47
|
+
|
48
|
+
steps
|
49
|
+
end
|
50
|
+
|
51
|
+
def html_escape text
|
52
|
+
require 'cgi'
|
53
|
+
|
54
|
+
CGI::escapeHTML(text)
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_wiki_links text
|
58
|
+
text.gsub(/-\w(.*?)\w>/) { |match| %{<a href="#{wiki_link match}">#{format_link_display(match)}</a>}}
|
59
|
+
end
|
60
|
+
|
61
|
+
def wiki_link topic
|
62
|
+
permalink topic[1..-2]
|
63
|
+
end
|
64
|
+
|
65
|
+
def permalink topic
|
66
|
+
topic.gsub(%r{[^/\w\s\-]},'').gsub(%r{[^\w/]|[\_]},' ').split.join('-').downcase
|
67
|
+
end
|
68
|
+
|
69
|
+
def format_link_display text
|
70
|
+
text[1..-2].split("/").last
|
71
|
+
end
|
72
|
+
|
73
|
+
def convert_external_links text
|
74
|
+
text.gsub(/\[([^\|]*\|[^\]]*)\]/) { |match| build_external_link match }
|
75
|
+
end
|
76
|
+
|
77
|
+
def build_external_link match
|
78
|
+
text, url, title = match[1..-2].split("|", 3)
|
79
|
+
|
80
|
+
url = format_link url.strip
|
81
|
+
text.strip!
|
82
|
+
title.strip! if title
|
83
|
+
|
84
|
+
if title
|
85
|
+
%{<a href="#{url}" title="#{title}" target="_blank">#{text}</a>}
|
86
|
+
else
|
87
|
+
%{<a href="#{url}" target="_blank">#{text}</a>}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def format_link url
|
92
|
+
return url if /:\/\// =~ url
|
93
|
+
"http://#{url}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def format_list text
|
97
|
+
text.split(/^\*/).reject { |item| item == "" }.map { |item| wrap(item.chomp, "li") }.join("\n")
|
98
|
+
end
|
99
|
+
|
100
|
+
def parse_feed text
|
101
|
+
parser = Flannel::FeedParser.new Flannel.cache_params
|
102
|
+
parser.sub_feeds text
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Flannel
|
2
|
+
class TextBlock
|
3
|
+
attr_reader :style
|
4
|
+
|
5
|
+
def initialize text
|
6
|
+
set_style_marker text
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
@text
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
html_formatter = Flannel::HtmlFormatter.new
|
15
|
+
html_formatter.do(@text, @style)
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_style_marker text
|
19
|
+
case text[0]
|
20
|
+
when '_'[0] #preformatted
|
21
|
+
@style = :preformatted
|
22
|
+
@text = text[1..-1]
|
23
|
+
when '&'[0] #feed
|
24
|
+
@style = :feed
|
25
|
+
@text = text[1..-1]
|
26
|
+
when '*'[0] #list
|
27
|
+
@style = :list
|
28
|
+
@text = text
|
29
|
+
when '='[0] #header
|
30
|
+
match = text.match /^(=+)/
|
31
|
+
weight = match.captures[0].length
|
32
|
+
|
33
|
+
@style = "header_#{weight}".to_sym
|
34
|
+
@text = text[weight..-1]
|
35
|
+
else #other
|
36
|
+
@style = :paragraph
|
37
|
+
@text = text
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class
|
3
|
+
class BlockCutterTest < Test::Unit::TestCase
|
4
4
|
context "basic behavior" do
|
5
5
|
setup do
|
6
|
-
@
|
6
|
+
@block_cutter = Flannel::BlockCutter.new
|
7
7
|
end
|
8
8
|
|
9
9
|
should "split a flannel document into squares based on blank lines" do
|
10
10
|
markup = "foo\n\nbar"
|
11
11
|
|
12
|
-
squares = @
|
12
|
+
squares = @block_cutter.cut markup
|
13
13
|
assert_equal 2, squares.length
|
14
14
|
assert_equal "foo", squares[0].to_s
|
15
15
|
assert_equal "bar", squares[1].to_s
|
@@ -18,7 +18,7 @@ class ShearsTest < Test::Unit::TestCase
|
|
18
18
|
should "not split preformatted text based on blank lines" do
|
19
19
|
markup = "_foo\n\nbar\n_"
|
20
20
|
|
21
|
-
squares = @
|
21
|
+
squares = @block_cutter.cut markup
|
22
22
|
assert_equal 1, squares.length
|
23
23
|
assert_equal :preformatted, squares[0].style
|
24
24
|
end
|
@@ -27,7 +27,7 @@ class ShearsTest < Test::Unit::TestCase
|
|
27
27
|
should "separate preformatted blocks" do
|
28
28
|
markup = "_foo\n_\n\n_bar\n_"
|
29
29
|
|
30
|
-
squares = @
|
30
|
+
squares = @block_cutter.cut markup
|
31
31
|
assert_equal 2, squares.length
|
32
32
|
assert_equal :preformatted, squares[0].style
|
33
33
|
assert_equal :preformatted, squares[1].style
|
@@ -36,14 +36,14 @@ class ShearsTest < Test::Unit::TestCase
|
|
36
36
|
should "strip preformatted markers when found" do
|
37
37
|
markup = "_foo\n\nbar\n_"
|
38
38
|
|
39
|
-
squares = @
|
39
|
+
squares = @block_cutter.cut markup
|
40
40
|
assert_equal "foo\n\nbar", squares[0].to_s
|
41
41
|
end
|
42
42
|
|
43
43
|
should "set square style to feed based on ampersand " do
|
44
44
|
markup = "& http://www.example.com/rss"
|
45
45
|
|
46
|
-
squares = @
|
46
|
+
squares = @block_cutter.cut markup
|
47
47
|
assert_equal :feed, squares[0].style
|
48
48
|
end
|
49
49
|
end
|
data/test/cutting_board_test.rb
CHANGED
@@ -11,11 +11,6 @@ class CuttingBoardTest < Test::Unit::TestCase
|
|
11
11
|
assert_equal "<pre>foo\n\n bar</pre>", @board.cut(markup)
|
12
12
|
end
|
13
13
|
|
14
|
-
should "preformat text when both start and end line have the markers" do
|
15
|
-
markup = "_foo\n\n_ bar"
|
16
|
-
assert_equal "<pre>foo\n\n bar</pre>", @board.cut(markup)
|
17
|
-
end
|
18
|
-
|
19
14
|
should "not replace in preformatted text" do
|
20
15
|
markup = "_4 - 2 > 2 - 2\n_"
|
21
16
|
assert_equal '<pre>4 - 2 > 2 - 2</pre>', @board.cut(markup)
|
data/test/flannel_test.rb
CHANGED
@@ -9,4 +9,10 @@ class FlannelTest < Test::Unit::TestCase
|
|
9
9
|
should "return nil if text is nil" do
|
10
10
|
assert_nil Flannel.quilt(nil)
|
11
11
|
end
|
12
|
+
|
13
|
+
should "parse paragraphs correctly" do
|
14
|
+
input = "\nThis is paragraph one.\n\nThis is paragraph two.\n\nThis is paragraph three. Watchout for the end of file.\n"
|
15
|
+
output = "<p>This is paragraph one.</p>\n\n<p>This is paragraph two.</p>\n\n<p>This is paragraph three. Watchout for the end of file.</p>"
|
16
|
+
assert_equal output, Flannel.quilt(input)
|
17
|
+
end
|
12
18
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'flannel/stripe'
|
3
|
+
|
4
|
+
class HtmlFormatterTest < Test::Unit::TestCase
|
5
|
+
context "basic operations" do
|
6
|
+
setup do
|
7
|
+
@formatter = Flannel::HtmlFormatter.new
|
8
|
+
end
|
9
|
+
|
10
|
+
should "return html fragment with format" do
|
11
|
+
assert_equal "<p>foo</p>", @formatter.do('foo', :paragraph)
|
12
|
+
end
|
13
|
+
|
14
|
+
context "building wiki links" do
|
15
|
+
should "not be greedy in matching" do
|
16
|
+
result = @formatter.do "a -foo> and a -bar>.", :paragraph
|
17
|
+
assert_equal '<p>a <a href="foo">foo</a> and a <a href="bar">bar</a>.</p>', result
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "subdirectories" do
|
22
|
+
should "handle subdirectories and not display directory info" do
|
23
|
+
result = @formatter.do("I think it -cheese/tastes good>.", :paragraph)
|
24
|
+
assert_equal '<p>I think it <a href="cheese/tastes-good">tastes good</a>.</p>', result
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "links" do
|
29
|
+
should "output the link" do
|
30
|
+
assert_equal '<p><a href="cheese">cheese</a></p>', @formatter.do("-cheese>", :paragraph)
|
31
|
+
end
|
32
|
+
|
33
|
+
should "hyphenate words" do
|
34
|
+
result = @formatter.do("-cheese is good>", :paragraph)
|
35
|
+
assert_equal '<p><a href="cheese-is-good">cheese is good</a></p>', result
|
36
|
+
end
|
37
|
+
|
38
|
+
should "replace text surrounded by - and > with a wiki link" do
|
39
|
+
result = @formatter.do("red, -green>, refactor", :paragraph)
|
40
|
+
assert_equal '<p>red, <a href="green">green</a>, refactor</p>',result
|
41
|
+
end
|
42
|
+
|
43
|
+
should "not replace text surrounded by - and > with a wiki link if spaced" do
|
44
|
+
result = @formatter.do("red, - green >, refactor", :paragraph)
|
45
|
+
assert_equal '<p>red, - green >, refactor</p>', result
|
46
|
+
end
|
47
|
+
|
48
|
+
should "not replace text surrounded by - and > with a wiki link if spaced on right" do
|
49
|
+
result = @formatter.do("red, -green >, refactor", :paragraph)
|
50
|
+
assert_equal '<p>red, -green >, refactor</p>', result
|
51
|
+
end
|
52
|
+
|
53
|
+
should "not replace surrounded by - and > with a wiki link if spaced on left" do
|
54
|
+
result = @formatter.do("red, - green>, refactor", :paragraph)
|
55
|
+
assert_equal '<p>red, - green>, refactor</p>', result
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "preformatted text" do
|
60
|
+
should "html escape preformatted text" do
|
61
|
+
result = @formatter.do("<p>& foo</p>", :preformatted)
|
62
|
+
assert_equal "<pre><p>& foo</p></pre>", result
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "making permalinks" do
|
67
|
+
should "replace spaces with dashes" do
|
68
|
+
assert_equal "get-the-box", @formatter.permalink("get the box")
|
69
|
+
end
|
70
|
+
|
71
|
+
should "replace multiple spaces with single dashes" do
|
72
|
+
assert_equal "get-the-box", @formatter.permalink("get the box")
|
73
|
+
end
|
74
|
+
|
75
|
+
should "replace odd characters with dashes" do
|
76
|
+
assert_equal "get-the-box", @formatter.permalink("get the @#)(* box")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TextBlockTest < Test::Unit::TestCase
|
4
|
+
context "basic behavior" do
|
5
|
+
should "return html" do
|
6
|
+
text_block = Flannel::TextBlock.new "foo"
|
7
|
+
assert_equal "<p>foo</p>", text_block.to_h
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "style" do
|
12
|
+
should "recognize preformatted" do
|
13
|
+
text_block = Flannel::TextBlock.new "_foo"
|
14
|
+
assert_equal :preformatted, text_block.style
|
15
|
+
end
|
16
|
+
|
17
|
+
should "recognize paragraph" do
|
18
|
+
text_block = Flannel::TextBlock.new "foo"
|
19
|
+
assert_equal :paragraph, text_block.style
|
20
|
+
end
|
21
|
+
|
22
|
+
should "recognize list" do
|
23
|
+
text_block = Flannel::TextBlock.new "* foo/n* bar/n* baz"
|
24
|
+
assert_equal :list, text_block.style
|
25
|
+
end
|
26
|
+
|
27
|
+
should "recognize feed" do
|
28
|
+
text_block = Flannel::TextBlock.new "& http://foo.example.com"
|
29
|
+
assert_equal :feed, text_block.style
|
30
|
+
end
|
31
|
+
|
32
|
+
should "recognize header" do
|
33
|
+
text_block = Flannel::TextBlock.new "====My Header"
|
34
|
+
assert_equal :header_4, text_block.style
|
35
|
+
end
|
36
|
+
|
37
|
+
should "wrap in pre tags when preformatted" do
|
38
|
+
text_block = Flannel::TextBlock.new "_foo"
|
39
|
+
assert_equal "<pre>foo</pre>", text_block.to_h
|
40
|
+
end
|
41
|
+
|
42
|
+
should "wrap in ul tags when unordered_list" do
|
43
|
+
text_block = Flannel::TextBlock.new "* foo"
|
44
|
+
assert_equal "<ul><li>foo</li></ul>", text_block.to_h
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "external links" do
|
49
|
+
should "convert [|] pattern to an external link" do
|
50
|
+
text_block = Flannel::TextBlock.new "yadda [yadda|http://example.com] yadda"
|
51
|
+
assert_equal '<p>yadda <a href="http://example.com" target="_blank">yadda</a> yadda</p>', text_block.to_h
|
52
|
+
end
|
53
|
+
|
54
|
+
should "add http:// to external links" do
|
55
|
+
text_block = Flannel::TextBlock.new "yadda [yadda|example.com] yadda"
|
56
|
+
assert_equal '<p>yadda <a href="http://example.com" target="_blank">yadda</a> yadda</p>', text_block.to_h
|
57
|
+
end
|
58
|
+
|
59
|
+
should "add create title if provided to external links" do
|
60
|
+
text_block = Flannel::TextBlock.new "yadda [yadda|example.com|My title] yadda"
|
61
|
+
assert_equal '<p>yadda <a href="http://example.com" title="My title" target="_blank">yadda</a> yadda</p>', text_block.to_h
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flannel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamal Hansen
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-25 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -76,22 +76,22 @@ files:
|
|
76
76
|
- features/wiki_links.feature
|
77
77
|
- flannel.gemspec
|
78
78
|
- lib/flannel.rb
|
79
|
+
- lib/flannel/block_cutter.rb
|
79
80
|
- lib/flannel/cache_location_does_not_exist_error.rb
|
80
81
|
- lib/flannel/cutting_board.rb
|
81
82
|
- lib/flannel/feed_parser.rb
|
82
83
|
- lib/flannel/file_cache.rb
|
83
|
-
- lib/flannel/
|
84
|
-
- lib/flannel/
|
85
|
-
- lib/flannel/stripe.rb
|
84
|
+
- lib/flannel/html_formatter.rb
|
85
|
+
- lib/flannel/text_block.rb
|
86
86
|
- lib/flannel/wrappable.rb
|
87
|
+
- test/block_cutter_test.rb
|
87
88
|
- test/cutting_board_test.rb
|
88
89
|
- test/feed_parser_test.rb
|
89
90
|
- test/file_cache_test.rb
|
90
91
|
- test/flannel_test.rb
|
91
|
-
- test/
|
92
|
-
- test/square_test.rb
|
93
|
-
- test/stripe_test.rb
|
92
|
+
- test/html_formatter_test.rb
|
94
93
|
- test/test_helper.rb
|
94
|
+
- test/text_block_test.rb
|
95
95
|
has_rdoc: true
|
96
96
|
homepage: http://github.com/rubyyot/flannel
|
97
97
|
licenses: []
|
@@ -121,11 +121,11 @@ signing_key:
|
|
121
121
|
specification_version: 3
|
122
122
|
summary: A soft comfortable worn in markup language for Ruby
|
123
123
|
test_files:
|
124
|
+
- test/html_formatter_test.rb
|
125
|
+
- test/block_cutter_test.rb
|
124
126
|
- test/test_helper.rb
|
125
127
|
- test/file_cache_test.rb
|
126
|
-
- test/stripe_test.rb
|
127
128
|
- test/cutting_board_test.rb
|
129
|
+
- test/text_block_test.rb
|
128
130
|
- test/feed_parser_test.rb
|
129
131
|
- test/flannel_test.rb
|
130
|
-
- test/square_test.rb
|
131
|
-
- test/shears_test.rb
|
data/lib/flannel/shears.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
#require 'square'
|
2
|
-
#require 'stripe'
|
3
|
-
|
4
|
-
module Flannel
|
5
|
-
class Shears
|
6
|
-
def initialize params={}
|
7
|
-
@params = params
|
8
|
-
end
|
9
|
-
|
10
|
-
def cut markup
|
11
|
-
@squares = []
|
12
|
-
@square = Flannel::Square.new
|
13
|
-
@end_preformat = false
|
14
|
-
|
15
|
-
markup.split("\n").each { |line| cut_into_squares line }
|
16
|
-
|
17
|
-
@squares << @square
|
18
|
-
end
|
19
|
-
|
20
|
-
def cut_into_squares line
|
21
|
-
if need_new_square? line
|
22
|
-
shift_square
|
23
|
-
else
|
24
|
-
add line
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def shift_square
|
29
|
-
@squares << @square unless @square.blank?
|
30
|
-
@square = Flannel::Square.new @params
|
31
|
-
end
|
32
|
-
|
33
|
-
def need_new_square? line
|
34
|
-
@square.style == :preformatted ? @end_preformat : empty?(line.strip)
|
35
|
-
end
|
36
|
-
|
37
|
-
def add line
|
38
|
-
@preformatted_marker_line = false
|
39
|
-
line = strip_markers line
|
40
|
-
line = remove_hanging_preformatted_lines line
|
41
|
-
|
42
|
-
@square << line unless line.nil?
|
43
|
-
end
|
44
|
-
|
45
|
-
def remove_hanging_preformatted_lines line
|
46
|
-
if @preformatted_marker_line
|
47
|
-
@end_preformat = @square.populated?
|
48
|
-
if line.strip == ""
|
49
|
-
return nil
|
50
|
-
end
|
51
|
-
else
|
52
|
-
@end_preformat = false
|
53
|
-
end
|
54
|
-
line
|
55
|
-
end
|
56
|
-
|
57
|
-
def strip_markers line
|
58
|
-
parts = line.match(/^([=_*&]+)(.*)/)
|
59
|
-
|
60
|
-
if parts
|
61
|
-
set_style parts[1]
|
62
|
-
line = parts[2]
|
63
|
-
end
|
64
|
-
line
|
65
|
-
end
|
66
|
-
|
67
|
-
def set_style marker
|
68
|
-
if marker
|
69
|
-
case marker[0]
|
70
|
-
when 61 # equals (header)
|
71
|
-
style = "header_#{marker.length}"
|
72
|
-
@square.style = style.to_sym
|
73
|
-
when 95 # underscore (preformatted)
|
74
|
-
@square.style = :preformatted
|
75
|
-
@preformatted_marker_line = true
|
76
|
-
when 42 # star (list)
|
77
|
-
@square.style = :list
|
78
|
-
when 38 # ampersand (feed)
|
79
|
-
@square.style = :feed
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def empty? str
|
85
|
-
str.nil? || str == ""
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
data/lib/flannel/square.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
#require 'wrappable'
|
2
|
-
|
3
|
-
module Flannel
|
4
|
-
class Square
|
5
|
-
include Flannel::Wrappable
|
6
|
-
attr_accessor :style
|
7
|
-
|
8
|
-
def initialize params={}
|
9
|
-
@tags ={:preformatted => "pre", :feed => "ul", :list => "ul", :header_1 => "h1", :header_2 => "h2", :header_3 => "h3", :header_4 => "h4", :header_5 => "h5", :header_6 => "h6"}
|
10
|
-
@stripes = []
|
11
|
-
@style = :paragraph
|
12
|
-
@params = params
|
13
|
-
end
|
14
|
-
|
15
|
-
def << text
|
16
|
-
text = text.strip unless @style == :preformatted
|
17
|
-
@params[:style] = @style
|
18
|
-
@stripes << Flannel::Stripe.stitch(text, @params.dup)
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_s
|
22
|
-
@stripes.map { |stripe| stripe.weave }.join("\n")
|
23
|
-
end
|
24
|
-
|
25
|
-
def blank?
|
26
|
-
(@stripes.length == 0 || all_stripes_blank)
|
27
|
-
end
|
28
|
-
|
29
|
-
def populated?
|
30
|
-
!blank?
|
31
|
-
end
|
32
|
-
|
33
|
-
def all_stripes_blank
|
34
|
-
@stripes.each do |stripe|
|
35
|
-
return false if !stripe.empty?
|
36
|
-
end
|
37
|
-
|
38
|
-
return true
|
39
|
-
end
|
40
|
-
|
41
|
-
def to_h
|
42
|
-
@post_wrap = nil
|
43
|
-
lines = @stripes.map { |stripe| stripe.to_h }
|
44
|
-
|
45
|
-
quilt lines
|
46
|
-
end
|
47
|
-
|
48
|
-
def quilt lines
|
49
|
-
output = lines.join("\n")
|
50
|
-
output = convert_external_links output
|
51
|
-
return wrap(output, find_tag)
|
52
|
-
end
|
53
|
-
|
54
|
-
def preformatted
|
55
|
-
@style == :preformatted
|
56
|
-
end
|
57
|
-
|
58
|
-
def convert_external_links text
|
59
|
-
return text if preformatted
|
60
|
-
text.gsub(/\[([^\|]*\|[^\]]*)\]/) { |match| build_external_link match }
|
61
|
-
end
|
62
|
-
|
63
|
-
def build_external_link match
|
64
|
-
text, url, title = match[1..-2].split("|", 3)
|
65
|
-
|
66
|
-
url = format_link url.strip
|
67
|
-
text.strip!
|
68
|
-
title.strip! if title
|
69
|
-
|
70
|
-
if title
|
71
|
-
%{<a href="#{url}" title="#{title}" target="_blank">#{text}</a>}
|
72
|
-
else
|
73
|
-
%{<a href="#{url}" target="_blank">#{text}</a>}
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def format_link url
|
78
|
-
return url if /:\/\// =~ url
|
79
|
-
"http://#{url}"
|
80
|
-
end
|
81
|
-
|
82
|
-
def find_tag
|
83
|
-
if @style && @tags.has_key?(@style)
|
84
|
-
tag = @tags[@style]
|
85
|
-
else
|
86
|
-
tag = "p"
|
87
|
-
end
|
88
|
-
tag
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
data/lib/flannel/stripe.rb
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
|
2
|
-
module Flannel
|
3
|
-
class Stripe
|
4
|
-
include Wrappable
|
5
|
-
attr_reader :weave
|
6
|
-
|
7
|
-
def self.stitch weave="", params={}
|
8
|
-
Flannel::Stripe.new weave, params
|
9
|
-
end
|
10
|
-
|
11
|
-
def initialize weave="", params={}
|
12
|
-
@weave = weave
|
13
|
-
@params = params
|
14
|
-
end
|
15
|
-
|
16
|
-
def wiki_link topic
|
17
|
-
if @params[:wiki_link]
|
18
|
-
@params[:wiki_link].call(permalink topic)
|
19
|
-
else
|
20
|
-
permalink topic[1..-2]
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def permalink topic
|
25
|
-
topic.gsub(%r{[^/\w\s\-]},'').gsub(%r{[^\w/]|[\_]},' ').split.join('-').downcase
|
26
|
-
end
|
27
|
-
|
28
|
-
def empty?
|
29
|
-
@weave == nil || @weave.strip == ""
|
30
|
-
end
|
31
|
-
|
32
|
-
def build_wiki_links
|
33
|
-
return @weave if preformatted
|
34
|
-
@weave.gsub(/-\w(.*?)\w>/) { |match| %{<a href="#{wiki_link match}">#{format_link_display(match)}</a>}}
|
35
|
-
end
|
36
|
-
|
37
|
-
def format_link_display text
|
38
|
-
text[1..-2].split("/").last
|
39
|
-
end
|
40
|
-
|
41
|
-
def to_h
|
42
|
-
|
43
|
-
if feed
|
44
|
-
parser = Flannel::FeedParser.new @params
|
45
|
-
parser.sub_feeds @weave
|
46
|
-
else
|
47
|
-
text = build_wiki_links
|
48
|
-
markup text
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def preformatted
|
53
|
-
@params[:style] == :preformatted
|
54
|
-
end
|
55
|
-
|
56
|
-
def list
|
57
|
-
@params[:style] == :list
|
58
|
-
end
|
59
|
-
|
60
|
-
def feed
|
61
|
-
@params[:style] == :feed
|
62
|
-
end
|
63
|
-
|
64
|
-
def markup text
|
65
|
-
return html_escape text if preformatted
|
66
|
-
|
67
|
-
tag = "li" if list
|
68
|
-
wrap(text, tag)
|
69
|
-
end
|
70
|
-
|
71
|
-
def html_escape text
|
72
|
-
require 'cgi'
|
73
|
-
|
74
|
-
CGI::escapeHTML(text)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
data/test/square_test.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class SquareTest < Test::Unit::TestCase
|
4
|
-
context "basic behavior" do
|
5
|
-
setup do
|
6
|
-
@square = Flannel::Square.new
|
7
|
-
end
|
8
|
-
|
9
|
-
should "accept strings with <<" do
|
10
|
-
@square << "foo"
|
11
|
-
assert_equal "foo", @square.to_s
|
12
|
-
end
|
13
|
-
|
14
|
-
should "be blank when there are no stripes" do
|
15
|
-
assert @square.blank?
|
16
|
-
@square << "foo"
|
17
|
-
assert !@square.blank?
|
18
|
-
end
|
19
|
-
|
20
|
-
should "be blank when the first stripe is an empty string" do
|
21
|
-
@square << ""
|
22
|
-
assert @square.blank?
|
23
|
-
end
|
24
|
-
|
25
|
-
should "be blank when the first stripe is whitespace" do
|
26
|
-
@square << " "
|
27
|
-
assert @square.blank?
|
28
|
-
end
|
29
|
-
|
30
|
-
should "be blank when the all stripes are empty strings" do
|
31
|
-
@square << ""
|
32
|
-
@square << ""
|
33
|
-
@square << ""
|
34
|
-
assert @square.blank?
|
35
|
-
end
|
36
|
-
|
37
|
-
should "be blank when the all stripes are whitespace" do
|
38
|
-
@square << " "
|
39
|
-
@square << " "
|
40
|
-
@square << ""
|
41
|
-
assert @square.blank?
|
42
|
-
end
|
43
|
-
|
44
|
-
should "not be blank when a stripe is not blank" do
|
45
|
-
@square << " "
|
46
|
-
@square << " "
|
47
|
-
@square << "foo"
|
48
|
-
assert !@square.blank?
|
49
|
-
end
|
50
|
-
|
51
|
-
should "return html" do
|
52
|
-
@square << "foo"
|
53
|
-
assert_equal "<p>foo</p>", @square.to_h
|
54
|
-
end
|
55
|
-
|
56
|
-
should "accept a style" do
|
57
|
-
@square.style = :preformatted
|
58
|
-
assert_equal :preformatted, @square.style
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
context "style" do
|
63
|
-
should "accept an optional style parameter" do
|
64
|
-
square = Flannel::Square.new
|
65
|
-
square.style = :foo
|
66
|
-
end
|
67
|
-
|
68
|
-
should "wrap in pre tags when preformatted" do
|
69
|
-
square = Flannel::Square.new
|
70
|
-
square.style = :preformatted
|
71
|
-
square << "foo"
|
72
|
-
assert_equal "<pre>foo</pre>", square.to_h
|
73
|
-
end
|
74
|
-
|
75
|
-
should "wrap in ul tags when unordered_list" do
|
76
|
-
square = Flannel::Square.new
|
77
|
-
square.style = :list
|
78
|
-
square << "foo"
|
79
|
-
assert_equal "<ul><li>foo</li></ul>", square.to_h
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
context "external links" do
|
84
|
-
should "convert [|] pattern to an external link" do
|
85
|
-
square = Flannel::Square.new
|
86
|
-
square << "yadda [yadda|http://example.com] yadda"
|
87
|
-
assert_equal '<p>yadda <a href="http://example.com" target="_blank">yadda</a> yadda</p>', square.to_h
|
88
|
-
end
|
89
|
-
|
90
|
-
should "add http:// to external links" do
|
91
|
-
square = Flannel::Square.new
|
92
|
-
square << "yadda [yadda|example.com] yadda"
|
93
|
-
assert_equal '<p>yadda <a href="http://example.com" target="_blank">yadda</a> yadda</p>', square.to_h
|
94
|
-
end
|
95
|
-
|
96
|
-
should "add create title if provided to external links" do
|
97
|
-
square = Flannel::Square.new
|
98
|
-
square << "yadda [yadda|example.com|My title] yadda"
|
99
|
-
assert_equal '<p>yadda <a href="http://example.com" title="My title" target="_blank">yadda</a> yadda</p>', square.to_h
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
data/test/stripe_test.rb
DELETED
@@ -1,126 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'flannel/stripe'
|
3
|
-
|
4
|
-
class StripeTest < Test::Unit::TestCase
|
5
|
-
context "basic operations" do
|
6
|
-
setup do
|
7
|
-
@stripe = Flannel::Stripe.stitch "foo"
|
8
|
-
end
|
9
|
-
|
10
|
-
should "be of of kind Flannel::Stripe" do
|
11
|
-
assert Flannel::Stripe, @stripe.class
|
12
|
-
end
|
13
|
-
|
14
|
-
should "create instance with stitch" do
|
15
|
-
assert_equal "foo", @stripe.weave
|
16
|
-
end
|
17
|
-
|
18
|
-
should "return html fragment with to_h" do
|
19
|
-
assert_equal "foo", @stripe.to_h
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
context "building wiki links" do
|
24
|
-
setup do
|
25
|
-
wiki_link = lambda { |keyword| "http://www.example.com/foo/#{keyword}"}
|
26
|
-
@stripe = Flannel::Stripe.stitch "the -roof is on fire>", :wiki_link => wiki_link
|
27
|
-
end
|
28
|
-
|
29
|
-
should "build wiki links based on a lambda" do
|
30
|
-
assert_equal "http://www.example.com/foo/cheese",
|
31
|
-
@stripe.wiki_link("-cheese>")
|
32
|
-
end
|
33
|
-
|
34
|
-
should "find and replace wiki link markup" do
|
35
|
-
assert_equal 'the <a href="http://www.example.com/foo/roof-is-on-fire">roof is on fire</a>',
|
36
|
-
@stripe.to_h
|
37
|
-
end
|
38
|
-
|
39
|
-
should "permalink topics when making wiki links" do
|
40
|
-
assert_equal "http://www.example.com/foo/cheese-tastes-good",
|
41
|
-
@stripe.wiki_link("-cheese tastes good>")
|
42
|
-
end
|
43
|
-
|
44
|
-
should "not be greedy in matching" do
|
45
|
-
stripe = Flannel::Stripe.stitch("a -foo> and a -bar>.")
|
46
|
-
assert_equal 'a <a href="foo">foo</a> and a <a href="bar">bar</a>.', stripe.build_wiki_links
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context "subdirectories" do
|
51
|
-
setup do
|
52
|
-
@stripe = Flannel::Stripe.stitch "I think it -cheese/tastes good>."
|
53
|
-
end
|
54
|
-
|
55
|
-
should "handle subdirectories" do
|
56
|
-
assert_equal "cheese/tastes-good", @stripe.wiki_link("-cheese/tastes good>")
|
57
|
-
end
|
58
|
-
|
59
|
-
should "not display directory info" do
|
60
|
-
assert_equal 'I think it <a href="cheese/tastes-good">tastes good</a>.', @stripe.build_wiki_links
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
context "no lambda is provided" do
|
65
|
-
setup do
|
66
|
-
@stripe = Flannel::Stripe.stitch "baz"
|
67
|
-
end
|
68
|
-
|
69
|
-
should "output the wiki text" do
|
70
|
-
assert_equal "cheese", @stripe.wiki_link("-cheese>")
|
71
|
-
end
|
72
|
-
|
73
|
-
should "prermalink the wiki text" do
|
74
|
-
assert_equal "cheese-is-good", @stripe.wiki_link("-cheese is good>")
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
context "replacing wiki links" do
|
79
|
-
should "replace surrounded by - and > with a wiki link" do
|
80
|
-
stripe = Flannel::Stripe.stitch("red, -green>, refactor")
|
81
|
-
assert_equal 'red, <a href="green">green</a>, refactor', stripe.to_h
|
82
|
-
end
|
83
|
-
|
84
|
-
should "not replace surrounded by - and > with a wiki link if spaced" do
|
85
|
-
stripe = Flannel::Stripe.stitch("red, - green >, refactor")
|
86
|
-
assert_equal 'red, - green >, refactor', stripe.to_h
|
87
|
-
end
|
88
|
-
|
89
|
-
should "not replace surrounded by - and > with a wiki link if spaced on
|
90
|
-
right" do
|
91
|
-
stripe = Flannel::Stripe.stitch("red, -green >, refactor")
|
92
|
-
assert_equal 'red, -green >, refactor', stripe.to_h
|
93
|
-
end
|
94
|
-
|
95
|
-
should "not replace surrounded by - and > with a wiki link if spaced on
|
96
|
-
left" do
|
97
|
-
stripe = Flannel::Stripe.stitch("red, - green>, refactor")
|
98
|
-
assert_equal 'red, - green>, refactor', stripe.to_h
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
context "preformatted text" do
|
103
|
-
should "html escape preformatted text" do
|
104
|
-
stripe = Flannel::Stripe.stitch "<p>& foo</p>", :style => :preformatted
|
105
|
-
assert_equal "<p>& foo</p>", stripe.to_h
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
context "making permalinks" do
|
110
|
-
setup do
|
111
|
-
@stripe = Flannel::Stripe.stitch ""
|
112
|
-
end
|
113
|
-
|
114
|
-
should "replace spaces with dashes" do
|
115
|
-
assert_equal "get-the-box", @stripe.permalink("get the box")
|
116
|
-
end
|
117
|
-
|
118
|
-
should "replace multiple spaces with single dashes" do
|
119
|
-
assert_equal "get-the-box", @stripe.permalink("get the box")
|
120
|
-
end
|
121
|
-
|
122
|
-
should "replace odd characters with dashes" do
|
123
|
-
assert_equal "get-the-box", @stripe.permalink("get the @#)(* box")
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|