qipowl 0.9.3 → 0.9.7
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.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +157 -76
- data/bin/bowler +4 -2
- data/config/bowlers/html.yaml +24 -9
- data/extras/drafts/parsing.md +53 -42
- data/features/bowler.feature +14 -0
- data/features/html.feature +76 -27
- data/features/step_definitions/bowler_steps.rb +20 -0
- data/lib/qipowl.rb +29 -19
- data/lib/qipowl/bowlers/html.rb +148 -96
- data/lib/qipowl/bowlers/i_sp_ru.rb +9 -9
- data/lib/qipowl/constants.rb +2 -1
- data/lib/qipowl/core/bowler.rb +31 -22
- data/lib/qipowl/core/mapper.rb +20 -22
- data/lib/qipowl/core/monkeypatches.rb +18 -25
- data/lib/qipowl/core/ruler.rb +48 -43
- data/lib/qipowl/version.rb +1 -1
- data/qipowl.gemspec +0 -2
- data/spec/html_additional_test.yaml +3 -0
- metadata +2 -35
data/features/bowler.feature
CHANGED
@@ -6,3 +6,17 @@ Feature: Mapper-Ruler-Bowler abstraction produces valid bowlers
|
|
6
6
|
Given we use "html" bowler
|
7
7
|
When the input string is ""
|
8
8
|
Then bowler has all the method aliases
|
9
|
+
|
10
|
+
Scenario: Config params set properly
|
11
|
+
Given nothing
|
12
|
+
When we request param "bowlers"
|
13
|
+
Then param value ends with "/qipowl/config/bowlers"
|
14
|
+
|
15
|
+
Scenario: Additional map mergeg properly
|
16
|
+
Given we add additional bowler directory "spec"
|
17
|
+
And we use "html" bowler with additional map "html_additional_test"
|
18
|
+
When the input string is "This is ⌚striked⌚ out."
|
19
|
+
And the execute method is called on bowler
|
20
|
+
Then the result should equal to "<p>This is <del>striked</del> out.</p>"
|
21
|
+
|
22
|
+
|
data/features/html.feature
CHANGED
@@ -46,11 +46,16 @@ Feature: All the possibilities of HTML parser
|
|
46
46
|
|
47
47
|
Scenario: Block tag Λ
|
48
48
|
Given we use "html" bowler
|
49
|
-
When the input string is
|
49
|
+
When the input string is
|
50
|
+
"""
|
51
|
+
Λ ruby
|
52
|
+
@mapping[:block] = ≡bold≡
|
53
|
+
Λ
|
54
|
+
"""
|
50
55
|
And the execute method is called on bowler
|
51
56
|
Then the result should equal to
|
52
57
|
"""
|
53
|
-
|
58
|
+
|
54
59
|
<pre class='ruby'>@mapping[:block] = ≡bold≡</pre>
|
55
60
|
"""
|
56
61
|
|
@@ -106,7 +111,7 @@ Feature: All the possibilities of HTML parser
|
|
106
111
|
| "Wikipedia¹http://wikipedia.org" | "<p><a href='http://wikipedia.org'>Wikipedia</a></p>" |
|
107
112
|
| "Wikipedia†Best knowledge base†" | "<p><abbr title='Best knowledge base'>Wikipedia</abbr></p>" |
|
108
113
|
| "Inplace picture¹http://mudasobwa.ru/images/am.jpg goes here." | "<p><img class='inplace' alt='Inplace picture' src='http://mudasobwa.ru/images/am.jpg'/> goes here.</p>" |
|
109
|
-
| "http://mudasobwa.ru/images/am.jpg Standalone picture" | " ␍ <figure> ␍
|
114
|
+
| "http://mudasobwa.ru/images/am.jpg Standalone picture" | " ␍ <figure> ␍ <img src='http://mudasobwa.ru/images/am.jpg'/> ␍ <figcaption> ␍ <p>Standalone picture</p> ␍ </figcaption> ␍ </figure> ␍ " |
|
110
115
|
|
111
116
|
Scenario Outline: Markdown atavisms ⇒ links
|
112
117
|
Given we use "html" bowler
|
@@ -117,7 +122,7 @@ Feature: All the possibilities of HTML parser
|
|
117
122
|
Examples:
|
118
123
|
| input | output |
|
119
124
|
| "Here  goes" | "<p>Here <img class='inplace' alt='Image' src='http://mudasobwa.ru/images/am.jpg'/> goes</p>" |
|
120
|
-
| "" | " ␍ <figure> ␍
|
125
|
+
| "" | " ␍ <figure> ␍ <img src='http://mudasobwa.ru/images/am.jpg'/> ␍ <figcaption> ␍ <p>Figure</p> ␍ </figcaption> ␍ </figure> ␍ " |
|
121
126
|
| "Here [Link](http://wikipedia.org/) goes" | "<p>Here <a href='http://wikipedia.org/'>Link</a> goes</p>" |
|
122
127
|
| "Here *italic* goes" | "<p>Here <em>italic</em> goes</p>" |
|
123
128
|
| "Here inplace*it*alic goes" | "<p>Here inplace<em>it</em>alic goes</p>" |
|
@@ -135,12 +140,12 @@ Feature: All the possibilities of HTML parser
|
|
135
140
|
|
136
141
|
Examples:
|
137
142
|
| input | output |
|
138
|
-
| "List: • li1 • li2" | "<p>List:</p> <ul class='fancy'><li>li1
|
139
|
-
| "List: • li1 • nested 1 • nested 2 • li2" | "<p>List:</p> <ul class='fancy'><li>li1
|
140
|
-
| "Data: ▶ dt — dd ▶ dt — dd" | "<p>Data:</p> <dl> ␍ <dt>dt</dt> ␍ <dd>dd
|
143
|
+
| "List: • li1 • li2" | "<p>List:</p> <ul class='fancy'><li>li1</li> <li>li2</li></ul>" |
|
144
|
+
| "List: • li1 • nested 1 • nested 2 • li2" | "<p>List:</p> <ul class='fancy'><li>li1</li> <ul class='fancy'><li>nested 1</li> <li>nested 2</li></ul> <li>li2</li></ul>" |
|
145
|
+
| "Data: ▶ dt — dd ▶ dt — dd" | "<p>Data:</p> <dl> ␍ <dt>dt</dt> ␍ <dd>dd</dd> ␍ ␍ <dt>dt</dt> ␍ <dd>dd</dd> ␍ </dl>" |
|
141
146
|
| "§1 Header" | "<h1>Header</h1>" |
|
142
147
|
| "〉 Blockquote" | "<blockquote><p class='blockquote'>Blockquote</p></blockquote>" |
|
143
|
-
|
148
|
+
|
144
149
|
Scenario Outline: Self tags
|
145
150
|
Given we use "html" bowler
|
146
151
|
When the input string is <input>
|
@@ -148,8 +153,12 @@ Feature: All the possibilities of HTML parser
|
|
148
153
|
Then the result should equal to <output>
|
149
154
|
|
150
155
|
Examples:
|
151
|
-
| input
|
152
|
-
| "here qipowl goes"
|
156
|
+
| input | output |
|
157
|
+
| "here qipowl goes" | "<p>here <strong><a href='http://qipowl.github.com'>qipowl</a></strong> goes</p>" |
|
158
|
+
| "here Qipowl goes" | "<p>here <strong><a href='http://Qipowl.github.com'>Qipowl</a></strong> goes</p>" |
|
159
|
+
| "here tag goes" | "<p>here <a href='/tags/tag'>tag</a> goes</p>" |
|
160
|
+
| "here tag2 goes" | "<p>here <b><a href='/tags/tag2'>tag2</a></b> goes</p>" |
|
161
|
+
| "here tag3 goes" | "<p>here <b><a href='/tags/tag3'>tag3</a></b> goes</p>" |
|
153
162
|
|
154
163
|
Scenario: Address tag
|
155
164
|
Given we use "html" bowler
|
@@ -162,7 +171,7 @@ Feature: All the possibilities of HTML parser
|
|
162
171
|
When the input string is "List: × li1 line item × li2"
|
163
172
|
And rule "×" is added to mapping as "li" in "regular" section with "ol" enclosure
|
164
173
|
And the execute method is called on bowler
|
165
|
-
Then the result should equal to "<p>List:</p> <ol><li>li1 line item
|
174
|
+
Then the result should equal to "<p>List:</p> <ol><li>li1 line item</li> <li>li2</li></ol>"
|
166
175
|
|
167
176
|
Scenario: Entity removal
|
168
177
|
Given we use "html" bowler
|
@@ -178,19 +187,19 @@ Feature: All the possibilities of HTML parser
|
|
178
187
|
✍
|
179
188
|
Preamble: given
|
180
189
|
✍
|
181
|
-
|
190
|
+
|
182
191
|
〉 http://mudasobwa.ru/i/self.jpg With caption
|
183
192
|
‒ Wiki, http://wikipedia.ru
|
184
|
-
|
193
|
+
|
185
194
|
Nice?
|
186
195
|
"""
|
187
196
|
And the execute method is called on bowler
|
188
197
|
Then the result should equal to
|
189
198
|
"""
|
190
|
-
|
191
|
-
|
199
|
+
|
200
|
+
|
192
201
|
<blockquote><p class='blockquote'>http://mudasobwa.ru/i/self.jpg With caption
|
193
|
-
<br/> <small><a href='http://wikipedia.ru'>Wiki</a></small
|
202
|
+
<br/> <small><a href='http://wikipedia.ru'>Wiki</a></small></p></blockquote>
|
194
203
|
<p>Nice?</p>
|
195
204
|
"""
|
196
205
|
|
@@ -201,13 +210,13 @@ Feature: All the possibilities of HTML parser
|
|
201
210
|
---
|
202
211
|
This is a comment text
|
203
212
|
---
|
204
|
-
|
213
|
+
|
205
214
|
Nice?
|
206
215
|
"""
|
207
216
|
And the execute method is called on bowler
|
208
217
|
Then the result should equal to
|
209
218
|
"""
|
210
|
-
|
219
|
+
|
211
220
|
<p>Nice?</p>
|
212
221
|
"""
|
213
222
|
|
@@ -216,28 +225,28 @@ Feature: All the possibilities of HTML parser
|
|
216
225
|
When the input string is
|
217
226
|
"""
|
218
227
|
§2 Blockquotes
|
219
|
-
|
228
|
+
|
220
229
|
〉 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere
|
221
230
|
erat a ante.
|
222
231
|
〉 Nested blockquote first line
|
223
232
|
〉 Nested blockquote second line
|
224
233
|
〉 Lorem ipsum para text 2.
|
225
|
-
|
234
|
+
|
226
235
|
Some para text.
|
227
|
-
|
236
|
+
|
228
237
|
〉 Intro 1.
|
229
238
|
• list item ≡with bold≡ 1
|
230
|
-
• list item ≈emphasized≈
|
239
|
+
• list item ≈emphasized≈
|
231
240
|
• nested list item 1
|
232
|
-
• nested list item 2
|
233
|
-
|
241
|
+
• nested list item 2
|
242
|
+
|
234
243
|
〉 Blockquote standalone.
|
235
|
-
|
244
|
+
|
236
245
|
〉 Intro 2.
|
237
|
-
• list item 2.1
|
246
|
+
• list item 2.1
|
238
247
|
• list item 2.2
|
239
248
|
〉 Continuing intro 2.
|
240
|
-
|
249
|
+
|
241
250
|
Blockquote standalone.
|
242
251
|
"""
|
243
252
|
And the execute method is called on bowler
|
@@ -245,3 +254,43 @@ Feature: All the possibilities of HTML parser
|
|
245
254
|
And the result should match "</li> <ul class='fancy'><li>nested list item 1"
|
246
255
|
And the result should match "<p>Blockquote standalone.</p>"
|
247
256
|
|
257
|
+
Scenario Outline: Postprocessing: spaces
|
258
|
+
Given we use "html" bowler
|
259
|
+
When the input string is <input>
|
260
|
+
And the execute method is called on bowler
|
261
|
+
Then the result should equal to <output>
|
262
|
+
|
263
|
+
Examples:
|
264
|
+
| input | output |
|
265
|
+
| "here «quote» goes" | "<p>here «quote» goes</p>" |
|
266
|
+
| "here « quote¹http://wikipedia.org » goes" | "<p>here «<a href='http://wikipedia.org'>quote</a>» goes</p>" |
|
267
|
+
| "This is λsystem.dllλ file." | "<p>This is <code>system.dll</code> file.</p>" |
|
268
|
+
| "This is ✓8:35✓ time." | "<p>This is <span class='notypo'>8:35</span> time.</p>" |
|
269
|
+
|
270
|
+
Scenario: Video embedded
|
271
|
+
Given we use "html" bowler
|
272
|
+
When the input string is
|
273
|
+
"""
|
274
|
+
http://qipowl.herokuapp.com/images/owl.png
|
275
|
+
|
276
|
+
☞ Video embedded:
|
277
|
+
|
278
|
+
http://www.youtube.com/watch?v=KFKxlYNfT_o
|
279
|
+
"""
|
280
|
+
And the execute method is called on bowler
|
281
|
+
Then the result should equal to
|
282
|
+
"""
|
283
|
+
|
284
|
+
<figure>
|
285
|
+
<img src='http://qipowl.herokuapp.com/images/owl.png'/>
|
286
|
+
<figcaption>
|
287
|
+
<p></p>
|
288
|
+
</figcaption>
|
289
|
+
</figure>
|
290
|
+
|
291
|
+
<p class='text-info'>Video embedded:</p>
|
292
|
+
|
293
|
+
<iframe class='youtube' width='560' height='315' src='http://www.youtube.com/embed/KFKxlYNfT_o'
|
294
|
+
frameborder='0' allowfullscreen></iframe>
|
295
|
+
|
296
|
+
"""
|
@@ -1,10 +1,17 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
Given(/^nothing$/) do
|
4
|
+
end
|
5
|
+
|
3
6
|
Given(/^we use "(.*?)" bowler$/) do |f|
|
4
7
|
# @f = "config/bowlers/#{f}.yaml"
|
5
8
|
@bowler = Qipowl::Ruler.new_bowler f
|
6
9
|
end
|
7
10
|
|
11
|
+
Given(/^we use "(.*?)" bowler with additional map "(.*?)"$/) do |f, map|
|
12
|
+
@bowler = Qipowl::Ruler.new_bowler(f, additional_maps: map)
|
13
|
+
end
|
14
|
+
|
8
15
|
When(/^the input string is "(.*?)"$/) do |input|
|
9
16
|
@input = input
|
10
17
|
end
|
@@ -25,6 +32,16 @@ When(/^rule "(.*?)" is removed from mapping$/) do |key|
|
|
25
32
|
@bowler.remove_entity key
|
26
33
|
end
|
27
34
|
|
35
|
+
When(/^we request param "(.*?)"$/) do |param|
|
36
|
+
@param_value = Qipowl["#{param}".to_sym]
|
37
|
+
end
|
38
|
+
|
39
|
+
When(/^we add additional bowler directory "(.*?)"$/) do |dir|
|
40
|
+
Qipowl::configure do
|
41
|
+
add :bowlers, dir
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
28
45
|
Then(/^bowler has all the method aliases$/) do
|
29
46
|
puts @bowler.class.instance_methods(false)
|
30
47
|
puts '='*60
|
@@ -39,3 +56,6 @@ Then(/^the output is "(.*?)"$/) do |result|
|
|
39
56
|
expect(@result).to eq(result)
|
40
57
|
end
|
41
58
|
|
59
|
+
Then(/^param value ends with "(.*?)"$/) do |s|
|
60
|
+
expect("#{@param_value}").to match(/#{s}$/)
|
61
|
+
end
|
data/lib/qipowl.rb
CHANGED
@@ -18,30 +18,40 @@ Encoding.default_internal = Encoding::UTF_8
|
|
18
18
|
module Qipowl
|
19
19
|
extend self
|
20
20
|
|
21
|
-
# Basic single-method DSL with .parameter method
|
22
|
-
# being used to define a set of available settings.
|
23
|
-
# This method takes one or more symbols, with each one being
|
24
|
-
# a name of the configuration option.
|
25
|
-
def params *names
|
26
|
-
names.each do |name|
|
27
|
-
attr_accessor name
|
28
|
-
define_method name do |*values|
|
29
|
-
value = values.first
|
30
|
-
value ? self.send("#{name}=", value) : instance_variable_get("@#{name}")
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
21
|
# A wrapper for the configuration block
|
36
|
-
def
|
22
|
+
def configure &block
|
37
23
|
instance_eval(&block)
|
38
24
|
end
|
39
25
|
|
26
|
+
def [](key)
|
27
|
+
config[key.to_sym]
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def set(key, value)
|
33
|
+
config[key.to_sym] = value
|
34
|
+
end
|
35
|
+
|
36
|
+
def add(key, value)
|
37
|
+
config[key.to_sym] = [*config[key.to_sym]] << value
|
38
|
+
end
|
39
|
+
|
40
|
+
def config
|
41
|
+
@config ||= Hash.new
|
42
|
+
end
|
43
|
+
|
44
|
+
def method_missing(sym, *args)
|
45
|
+
if sym.to_s =~ /(.+)=$/
|
46
|
+
config[$1.to_sym] = args.first
|
47
|
+
else
|
48
|
+
config[sym.to_sym]
|
49
|
+
end
|
50
|
+
end
|
40
51
|
end
|
41
52
|
|
42
|
-
Qipowl::
|
43
|
-
|
44
|
-
bowlers_dir File.expand_path(File.join(__dir__, '..', 'config', 'bowlers'))
|
53
|
+
Qipowl::configure do
|
54
|
+
set :bowlers, File.expand_path(File.join(__dir__, '..', 'config', 'bowlers'))
|
45
55
|
end
|
46
56
|
|
47
57
|
class Qipowl::Html
|
@@ -49,4 +59,4 @@ class Qipowl::Html
|
|
49
59
|
def self.parse s
|
50
60
|
(@bowler ||= Qipowl::Ruler.new_bowler "html").execute s
|
51
61
|
end
|
52
|
-
end
|
62
|
+
end
|
data/lib/qipowl/bowlers/html.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'net/http'
|
4
|
+
require 'base64'
|
4
5
|
require 'typogrowth'
|
5
6
|
|
6
7
|
require_relative '../core/bowler'
|
@@ -8,7 +9,7 @@ require_relative '../core/bowler'
|
|
8
9
|
module Qipowl
|
9
10
|
module Mappers
|
10
11
|
class HtmlBowlerMapper < BowlerMapper
|
11
|
-
|
12
|
+
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
@@ -23,59 +24,80 @@ module Qipowl
|
|
23
24
|
# @param [Array] args the words, gained since last call to {#harvest}
|
24
25
|
# @return [Array] the array of words with trimmed `grip` tag
|
25
26
|
def ∀_grip *args
|
27
|
+
data = ∃_grip(__callee__)
|
26
28
|
mine, rest = [*args].join(SEPARATOR).split("#{__callee__}∎", 2)
|
27
|
-
[tagify(
|
29
|
+
[tagify(data[:tag], {:class => data[:class]}, mine), rest]
|
28
30
|
end
|
29
31
|
|
30
32
|
# `:alone` default handler
|
31
33
|
# @param [Array] args the words, gained since last call to {#harvest}
|
32
34
|
# @return [Array] the array of words with prepended `alone` tag
|
33
35
|
def ∀_alone *args
|
34
|
-
|
36
|
+
data = ∃_alone(__callee__)
|
37
|
+
[standalone(data[:tag], {:class => data[:class]}), args]
|
35
38
|
end
|
36
39
|
|
37
40
|
# `:block` default handler
|
41
|
+
# FIXME TODO make an ability to supply class
|
38
42
|
# @param [Array] args the words, gained since last call to {#harvest}
|
39
43
|
# @param [String] param the text to be places on the same string as
|
40
44
|
# opening tag
|
41
45
|
# @return [Nil] nil
|
42
|
-
def ∀_block
|
43
|
-
|
44
|
-
param =
|
45
|
-
|
46
|
+
def ∀_block arg
|
47
|
+
data = ∃_block(__callee__)
|
48
|
+
param, body = Base64.decode64(
|
49
|
+
"#{arg.to_s.unbowl.uncarriage(false)}"
|
50
|
+
).force_encoding('UTF-8').split(/\n/, 2)
|
51
|
+
param, body = '', param if body.nil?
|
52
|
+
harvest __callee__,
|
46
53
|
tagify(
|
47
|
-
|
48
|
-
{:class =>
|
49
|
-
|
54
|
+
data[:tag],
|
55
|
+
{:class => param.strip.empty? ? data[:class] : param.strip },
|
56
|
+
body.hsub(String::HTML_ENTITIES)
|
50
57
|
)
|
51
58
|
end
|
52
|
-
|
59
|
+
|
53
60
|
# `:magnet` default handler
|
54
61
|
# @param [Array] args the words, gained since last call to {#harvest}
|
55
62
|
# @return [Array] the array of words with trimmed `magnet` tag
|
56
63
|
def ∀_magnet *args
|
64
|
+
data = ∃_magnet(__callee__)
|
57
65
|
param, *rest = args.flatten
|
58
66
|
param = param.unbowl.to_s.prepend("#{__callee__}#{String::NBSP}")
|
59
|
-
[tagify(
|
67
|
+
[tagify(data[:tag], {:class => data[:class]}, param), rest]
|
60
68
|
end
|
61
|
-
|
69
|
+
|
62
70
|
# `:regular` default handler
|
63
71
|
# @param [Array] args the words, gained since last call to {#harvest}
|
64
72
|
def ∀_regular *args
|
65
|
-
|
66
|
-
|
67
|
-
∃_regular_tag(canonize(__callee__)),
|
68
|
-
{:class => ∃_regular(canonize(__callee__))[:class]},
|
69
|
-
args
|
70
|
-
)
|
73
|
+
data = ∃_regular(canonize __callee__)
|
74
|
+
harvest __callee__, tagify(data[:tag], {:class => data[:class]}, args)
|
71
75
|
end
|
72
|
-
|
76
|
+
|
73
77
|
# `:self` default handler
|
74
78
|
# @param [Array] args the words, gained since last call to {#harvest}
|
75
|
-
def ∀_self *args
|
76
|
-
|
79
|
+
def ∀_self *args, &cb
|
80
|
+
data = ∃_self(__callee__)
|
81
|
+
cally = block_given? ? yield : __callee__
|
82
|
+
text = case data[:format]
|
83
|
+
when NilClass then cally
|
84
|
+
when String then cally.to_s.gsub(/(#{cally})/, data[:format])
|
85
|
+
# when Regexp then cally.to_s.gsub(cally.to_s, data[:format])
|
86
|
+
when Symbol then send(data[:format], cally) rescue cally # FIXME Do I need rescue here?!
|
87
|
+
else raise "Bad format specified for #{data[:tag]}"
|
88
|
+
end
|
89
|
+
[data[:tag] ? tagify(data[:tag], {:class => data[:class]}, text) : text, args]
|
90
|
+
end
|
91
|
+
|
92
|
+
##############################################################################
|
93
|
+
### Self :: Specific handlers ###
|
94
|
+
##############################################################################
|
95
|
+
# Handler for tags.
|
96
|
+
# @param [String] arg the word to be processed
|
97
|
+
# @return [Array] the array of words with procesed tag
|
98
|
+
def tagger_format tag
|
99
|
+
"<a href='/tags/#{tag}'>#{tag}</a>"
|
77
100
|
end
|
78
|
-
|
79
101
|
##############################################################################
|
80
102
|
### Grip :: Specific handlers ###
|
81
103
|
##############################################################################
|
@@ -83,28 +105,30 @@ module Qipowl
|
|
83
105
|
# @param [Array] args the words, gained since last call to {#harvest}
|
84
106
|
# @return [Array] the array of words with trimmed `abbr` tag
|
85
107
|
def † *args
|
108
|
+
data = ∃_grip(__callee__)
|
86
109
|
term, *title = args.flatten
|
87
110
|
mine, rest = [*title].join(SEPARATOR).split("#{__callee__}∎", 2)
|
88
|
-
[tagify(
|
111
|
+
[tagify(data[:tag], {:title => mine, :class => data[:class]}, term), rest]
|
89
112
|
end
|
90
113
|
|
91
114
|
# Handler for anchors.
|
92
115
|
# @param [Array] args the words, gained since last call to {#harvest}
|
93
116
|
# @return [Array] the array of words with trimmed `a` tag
|
94
117
|
def ⚓ *args
|
118
|
+
data = ∃_grip(__callee__)
|
95
119
|
href, *title = args.flatten
|
96
120
|
mine, rest = [*title].join(SEPARATOR).split("#{__callee__}∎", 2)
|
97
121
|
href = href.unbowl
|
98
122
|
[
|
99
123
|
case get_href_content(href)
|
100
|
-
when :img
|
124
|
+
when :img
|
101
125
|
standalone :img, { :src => href, :alt => [*mine].join(SEPARATOR), :class => 'inplace' }
|
102
|
-
else
|
103
|
-
tagify
|
126
|
+
else
|
127
|
+
tagify data[:tag], {:href => href}, mine
|
104
128
|
end, rest
|
105
129
|
]
|
106
130
|
end
|
107
|
-
|
131
|
+
|
108
132
|
##############################################################################
|
109
133
|
### Alone :: Specific handlers ###
|
110
134
|
##############################################################################
|
@@ -114,7 +138,7 @@ module Qipowl
|
|
114
138
|
# @return [Nil] nil
|
115
139
|
def —— *args
|
116
140
|
harvest nil, orphan(args.join(SEPARATOR)) unless args.vacant?
|
117
|
-
harvest __callee__, standalone(∃
|
141
|
+
harvest __callee__, standalone(∃_alone(__callee__)[:tag])
|
118
142
|
end
|
119
143
|
|
120
144
|
##############################################################################
|
@@ -142,12 +166,12 @@ module Qipowl
|
|
142
166
|
ljref = "<span style='white-space: nowrap;'><a href='http://#{param}.livejournal.com/profile?mode=full'><img src='http://l-stat.livejournal.com/img/userinfo.gif' alt='[info]' style='border: 0pt none ; vertical-align: bottom; padding-right: 1px;' height='17' width='17'></a><a href='http://#{param}.livejournal.com/?style=mine'><b>#{param}</b></a></span>"
|
143
167
|
[ljref, rest]
|
144
168
|
end
|
145
|
-
|
169
|
+
|
146
170
|
def ☇ *args
|
147
171
|
param, *rest = args.flatten
|
148
|
-
[tagify(∃
|
172
|
+
[tagify(∃_magnet(__callee__)[:tag], {:name => param.unbowl}, String::ZERO_WIDTH_SPACE), rest]
|
149
173
|
end
|
150
|
-
|
174
|
+
|
151
175
|
##############################################################################
|
152
176
|
### Regular :: Specific handlers ###
|
153
177
|
##############################################################################
|
@@ -158,25 +182,24 @@ module Qipowl
|
|
158
182
|
id, *rest = args.flatten
|
159
183
|
harvest nil, orphan(rest.join(SEPARATOR)) unless rest.vacant?
|
160
184
|
harvest __callee__, %Q(
|
161
|
-
<iframe class='youtube' width='560' height='315' src='http://www.youtube.com/embed/#{id.unbowl}'
|
185
|
+
<iframe class='youtube' width='560' height='315' src='http://www.youtube.com/embed/#{id.unbowl}'
|
162
186
|
frameborder='0' allowfullscreen></iframe>
|
163
187
|
)
|
164
188
|
end
|
165
|
-
|
189
|
+
|
166
190
|
# Handler for standalone pictures and
|
167
191
|
# @todo Make it to understand quotes when there is a plain HTML on the other side
|
168
|
-
#
|
169
|
-
# @param
|
192
|
+
#
|
193
|
+
# @param
|
170
194
|
# @return [Nil] nil
|
171
195
|
def ⚘ *args
|
172
196
|
href, *title = args.flatten
|
197
|
+
title = title.join(SEPARATOR).strip
|
173
198
|
harvest __callee__, %Q(
|
174
199
|
<figure>
|
175
200
|
<img src='#{href.unbowl}'/>
|
176
201
|
<figcaption>
|
177
|
-
<p>
|
178
|
-
#{title.join(SEPARATOR)}
|
179
|
-
</p>
|
202
|
+
<p>#{title}</p>
|
180
203
|
</figcaption>
|
181
204
|
</figure>
|
182
205
|
)
|
@@ -193,35 +216,61 @@ module Qipowl
|
|
193
216
|
#{tagify :dd, {}, dd}
|
194
217
|
)
|
195
218
|
end
|
196
|
-
# Alias for {#▶}, according to YAML rules specifies additional
|
219
|
+
# Alias for {#▶}, according to YAML rules specifies additional
|
197
220
|
# class for the data list `<dl>` tag behind (`dl-horizontal`.)
|
198
221
|
alias_method :▷, :▶
|
199
222
|
|
200
223
|
protected
|
224
|
+
def shadows
|
225
|
+
@shadows ||= ([] \
|
226
|
+
<< self.class::BLOCK_TAGS.keys.map {|b| /#{b}.*?#{b}/m } \
|
227
|
+
<< self.class::CUSTOM_TAGS.keys.map {|re| /#{re}/m} \
|
228
|
+
<< self.class::MAGNET_TAGS.keys.map {|m| /#{m}\s+\S+/} \
|
229
|
+
).flatten
|
230
|
+
end
|
231
|
+
|
201
232
|
# @see {Qipowl::Bowlers::Bowler#defreeze}
|
202
|
-
#
|
233
|
+
#
|
203
234
|
# @param [String] str to be defreezed
|
204
235
|
def defreeze str
|
205
|
-
|
236
|
+
s = shadows
|
237
|
+
str.typo(sections: [:sequence, :quotes], shadows: s).defuse(shadows: s)
|
206
238
|
end
|
207
239
|
|
240
|
+
def serveup str
|
241
|
+
s = [
|
242
|
+
/<pre.*?>.*?<\/pre>/m,
|
243
|
+
/<code.*?>.*?<\/code>/m
|
244
|
+
]
|
245
|
+
|
246
|
+
str.gsub(/⌦./, '').gsub(/.⌫/, '').typo(
|
247
|
+
sections: [:punctuation, :orphans], shadows: s
|
248
|
+
)
|
249
|
+
end
|
250
|
+
|
251
|
+
|
208
252
|
# Computes the level of the `:linewide` element by counting
|
209
253
|
# preceeding non-breakable spaces. For instance, nested lists
|
210
254
|
# are produced by appending `"\u{00A0}"` to the line item
|
211
|
-
# DSL tag:
|
212
|
-
#
|
255
|
+
# DSL tag:
|
256
|
+
#
|
213
257
|
# li = "• li1 \u{00A0}• nested 1 \u{00A0}• nested 2 • li2"
|
214
|
-
#
|
215
|
-
# @param [Symbol|String] callee the DSL symbol to get the level information for.
|
216
|
-
# @return [Integer] the level requested.
|
217
258
|
#
|
218
|
-
|
219
|
-
|
220
|
-
|
259
|
+
# @param [Symbol|String] cally the DSL symbol to get the level information for.
|
260
|
+
# @return [Integer] the level requested.
|
261
|
+
#
|
262
|
+
def level cally
|
263
|
+
(cally = cally.to_s).gsub(/#{String::NBSP}/, '').empty? ?
|
264
|
+
-1 : (0..cally.length-1).each { |i| break i if cally[i] != String::NBSP }
|
221
265
|
end
|
222
|
-
|
223
|
-
def canonize
|
224
|
-
|
266
|
+
|
267
|
+
def canonize cally
|
268
|
+
cally.to_s.gsub(/^#{String::NBSP}*/, '').to_sym if cally
|
269
|
+
end
|
270
|
+
|
271
|
+
def normalize cally
|
272
|
+
scally = cally.to_s.unbowl
|
273
|
+
scally.gsub(/\p{L}/, '').empty? ? scally.downcase.bowl.to_sym : cally
|
225
274
|
end
|
226
275
|
|
227
276
|
# Produces html paragraph tag (`<p>`) with no class.
|
@@ -233,70 +282,73 @@ module Qipowl
|
|
233
282
|
end
|
234
283
|
|
235
284
|
# @see Qipowl::Bowler#harvest
|
236
|
-
#
|
285
|
+
#
|
237
286
|
# Additionally it checks if there was a `:linewide` item, requiring
|
238
287
|
# surrounding html element (like `<ul>` aroung several `<li>`s.)
|
239
|
-
#
|
240
|
-
# @param [Symbol]
|
288
|
+
#
|
289
|
+
# @param [Symbol] cally of method
|
241
290
|
# @param [String] str to be harvested
|
242
|
-
def harvest
|
243
|
-
if
|
244
|
-
level(
|
291
|
+
def harvest cally, str
|
292
|
+
if cally.nil? || cally != @cally
|
293
|
+
level(cally).downto(level(@cally) + 1) { |i|
|
245
294
|
str += i.␚ify
|
246
|
-
} unless ∃_enclosures(canonize
|
247
|
-
|
248
|
-
if prev = ∃_enclosures(canonize(@
|
249
|
-
level(@
|
295
|
+
} unless ∃_enclosures(canonize cally).nil?
|
296
|
+
|
297
|
+
if prev = ∃_enclosures(canonize(@cally))
|
298
|
+
level(@cally).downto(level(cally) + 1) { |i|
|
250
299
|
@yielded.last.sub!(/\A/, opening(prev[:tag], {:class => prev[:class]}))
|
251
300
|
@yielded.each { |s| s.gsub!(/#{i.␚ify}/) { closing(prev[:tag]) } }
|
252
301
|
}
|
253
302
|
end
|
254
|
-
|
255
|
-
@
|
303
|
+
|
304
|
+
@cally = cally
|
256
305
|
end
|
257
|
-
super
|
306
|
+
super cally, str
|
258
307
|
end
|
259
308
|
|
260
309
|
private
|
261
|
-
# Hence we cannot simply declare the DSL for it, we need to handle
|
310
|
+
# Hence we cannot simply declare the DSL for it, we need to handle
|
262
311
|
# calls to all the _methods_, starting with those symbols.
|
263
|
-
#
|
312
|
+
#
|
264
313
|
# @param [Symbol] method as specified by caller (`method_missing`.)
|
265
314
|
# @param [Array] args as specified by caller (`method_missing`.)
|
266
315
|
# @param [Proc] block as specified by caller (`method_missing`.)
|
267
|
-
#
|
316
|
+
#
|
268
317
|
# @return [Array] the array of words
|
269
318
|
def special_handler method, *args, &block
|
270
319
|
# Sublevel markers, e.g. “ •” is level 2 line-item
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
self.class.
|
275
|
-
|
320
|
+
if level(method) > 0 && self.class::REGULAR_TAGS.keys.include?(m = (canonize method))
|
321
|
+
self.class.class_eval "alias_method :#{method}, :#{m}"
|
322
|
+
send method, args, block
|
323
|
+
elsif self.class.instance_methods.include?(m = (normalize method))
|
324
|
+
send(m, args) { yield if block_given? ; method.to_s }
|
325
|
+
else
|
326
|
+
[method, args].flatten
|
327
|
+
end
|
276
328
|
end
|
277
329
|
|
278
330
|
# Constructs opening html tag for the input given.
|
279
|
-
#
|
331
|
+
#
|
280
332
|
# To construct `abbr` tag with `title` _Title_ and class _default_:
|
281
|
-
#
|
333
|
+
#
|
282
334
|
# opening :abbr, { :title=>'Title', :class=>'default' }
|
283
|
-
#
|
335
|
+
#
|
284
336
|
# @param [String] tag to produce opening tag string from.
|
285
|
-
# @param [Hash] params to be put into opening tag as attributes.
|
337
|
+
# @param [Hash] params to be put into opening tag as attributes.
|
286
338
|
# @return [String] opening tag for the input given.
|
287
339
|
def opening tag, params={}
|
288
340
|
attrs = params.inject("") { |m, el| m.prepend " #{el.first}='#{el.last}'" unless el.last.nil? ; m }
|
289
341
|
"<#{tag}#{attrs}>"
|
290
342
|
end
|
291
|
-
|
343
|
+
|
292
344
|
# Constructs closing html tag for the input given.
|
293
|
-
#
|
345
|
+
#
|
294
346
|
# @param [String] tag to produce closing tag string from.
|
295
347
|
# @return [String] opening tag for the input given.
|
296
348
|
def closing tag
|
297
349
|
"</#{tag}>"
|
298
350
|
end
|
299
|
-
|
351
|
+
|
300
352
|
# (see opening)
|
301
353
|
# Acts most like an {#opening} method, but closes an element inplace
|
302
354
|
# (used for `hr`, `br`, `img`).
|
@@ -305,14 +357,14 @@ module Qipowl
|
|
305
357
|
end
|
306
358
|
# Constructs valid tag for the input given, concatenating
|
307
359
|
# opening and closing tags around the text passed in `args`.
|
308
|
-
#
|
360
|
+
#
|
309
361
|
# @param [String] tag to produce html tag string from.
|
310
|
-
# @param [Hash] params to be put into opening tag as attributes.
|
311
|
-
# @param [Array] args the words, to be tagged around.
|
362
|
+
# @param [Hash] params to be put into opening tag as attributes.
|
363
|
+
# @param [Array] args the words, to be tagged around.
|
312
364
|
# @return [String] opening tag for the input given.
|
313
365
|
def tagify tag, params, *args
|
314
366
|
text = [*args].join(SEPARATOR)
|
315
|
-
text.vacant? ? '' : "#{opening tag, params}#{text}#{closing tag}"
|
367
|
+
text.vacant? ? '' : "#{opening tag, params}#{text.strip}#{closing tag}"
|
316
368
|
end
|
317
369
|
|
318
370
|
|
@@ -329,7 +381,7 @@ module Qipowl
|
|
329
381
|
else
|
330
382
|
:text
|
331
383
|
end
|
332
|
-
|
384
|
+
|
333
385
|
# uri = URI(href.to_s.unbowl)
|
334
386
|
# Net::HTTP.start(uri.host, uri.port) do |http|
|
335
387
|
# http.open_timeout = 1
|
@@ -353,17 +405,17 @@ module Qipowl
|
|
353
405
|
end
|
354
406
|
=begin
|
355
407
|
# Markup processor for Html output.
|
356
|
-
#
|
408
|
+
#
|
357
409
|
# This class produces HTML from markup as Markdown does.
|
358
|
-
|
410
|
+
|
359
411
|
# Amount of unnamed instances of the class (needed for new class name generation)
|
360
412
|
@@inst_count = 0
|
361
|
-
|
362
|
-
|
413
|
+
|
414
|
+
|
363
415
|
# `:handshake` default handler
|
364
416
|
# @param [String] from packed as string operand “before”
|
365
417
|
# @param [String] from packed as string operand “after”
|
366
|
-
# @return
|
418
|
+
# @return
|
367
419
|
def ∈ *args
|
368
420
|
from, till, *rest = args.flatten
|
369
421
|
tag = @mapping.handshake(__callee__)
|
@@ -371,13 +423,13 @@ end
|
|
371
423
|
[tagify(tag, {}, "#{from.unbowl}#{__callee__}#{till.unbowl}".gsub(String::SYMBOL_FOR_SPACE, ' ')), rest]
|
372
424
|
end
|
373
425
|
alias_method :⊂, :∈
|
374
|
-
|
375
426
|
|
376
|
-
|
427
|
+
|
428
|
+
|
377
429
|
# @see {Qipowl::Bowler#serveup}
|
378
430
|
#
|
379
431
|
# Additionally it beatifies the output HTML
|
380
|
-
#
|
432
|
+
#
|
381
433
|
# @param [String] str to be roasted
|
382
434
|
def serveup str
|
383
435
|
result = ''
|
@@ -402,11 +454,11 @@ end
|
|
402
454
|
end
|
403
455
|
|
404
456
|
if __FILE__ == $0
|
405
|
-
|
457
|
+
|
406
458
|
i = 0
|
407
459
|
Dir.glob("#{File.dirname(__FILE__)}/../../../data/octopress-site/source/_posts/**/*.owl").each {|f|
|
408
460
|
puts "Processing ##{i += 1}: #{f}"
|
409
461
|
Qipowl::Html.parse File.read(f)
|
410
462
|
}
|
411
463
|
end
|
412
|
-
=end
|
464
|
+
=end
|