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.
@@ -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
+
@@ -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 "Λ ruby @mapping[:block] = ≡bold≡ Λ"
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> ␍ <img src='http://mudasobwa.ru/images/am.jpg'/> ␍ <figcaption> ␍ <p>Standalone picture</p> ␍ </figcaption> ␍ </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 ![Image](http://mudasobwa.ru/images/am.jpg) goes" | "<p>Here <img class='inplace' alt='Image' src='http://mudasobwa.ru/images/am.jpg'/> goes</p>" |
120
- | "![Figure](http://mudasobwa.ru/images/am.jpg)" | " ␍ <figure> ␍ <img src='http://mudasobwa.ru/images/am.jpg'/> ␍ <figcaption> ␍ <p>Figure</p> ␍ </figcaption> ␍ </figure> ␍ " |
125
+ | "![Figure](http://mudasobwa.ru/images/am.jpg)" | " ␍ <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 </li> <li>li2</li></ul>" |
139
- | "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>" |
140
- | "Data: ▶ dt — dd ▶ dt — dd" | "<p>Data:</p> <dl> ␍ <dt>dt</dt> ␍ <dd>dd </dd> ␍ ␍ <dt>dt</dt> ␍ <dd>dd</dd> ␍ </dl>" |
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 | output |
152
- | "here qipowl goes" | "<p>here <strong>qipowl</strong> goes</p>" |
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 </li> <li>li2</li></ol>"
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> </p></blockquote>
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 config &block
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::config do
43
- params :bowlers_dir
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
@@ -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(∃_grip_tag(__callee__), {:class => ∃_grip(__callee__)[:class]}, mine), rest]
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
- [standalone(∃_alone_tag(__callee__), {:class => ∃_alone(__callee__)[:class]}), args]
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 *args
43
- param, *args = args.flatten
44
- param = param.to_s
45
- harvest __callee__,
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
- ∃_block_tag(__callee__),
48
- {:class => (param.strip.empty? ? ∃_block(__callee__)[:class] : param.strip)},
49
- args.join(SEPARATOR).hsub(String::HTML_ENTITIES)
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(∃_magnet_tag(__callee__), {:class => ∃_magnet(__callee__)[:class]}, param), rest]
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
- harvest __callee__,
66
- tagify(
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
- [tagify(∃_self_tag(__callee__), {:class => ∃_self(__callee__)[:class]}, __callee__), args]
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(∃_grip_tag(__callee__), {:title => mine, :class => ∃_grip(__callee__)[:class]}, term), rest]
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 ∃_grip_tag(__callee__), {:href => href}, mine
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(∃_alone_tag(__callee__))
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(∃_magnet_tag(__callee__), {:name => param.unbowl}, String::ZERO_WIDTH_SPACE), rest]
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
- (super str)
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
- def level callee
219
- (callee = callee.to_s).gsub(/#{String::NBSP}/, '').empty? ?
220
- -1 : (0..callee.length-1).each { |i| break i if callee[i] != String::NBSP }
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 callee
224
- callee.to_s.gsub(/^#{String::NBSP}*/, '').to_sym if callee
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] callee of method
288
+ #
289
+ # @param [Symbol] cally of method
241
290
  # @param [String] str to be harvested
242
- def harvest callee, str
243
- if callee.nil? || callee != @callee
244
- level(callee).downto(level(@callee) + 1) { |i|
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(callee)).nil?
247
-
248
- if prev = ∃_enclosures(canonize(@callee))
249
- level(@callee).downto(level(callee) + 1) { |i|
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
- @callee = callee
303
+
304
+ @cally = cally
256
305
  end
257
- super callee, str
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
- return [method, args].flatten \
272
- unless level(method) > 0 && self.class::REGULAR_TAGS.keys.include?(canonize(method))
273
-
274
- self.class.class_eval "alias_method :#{method}, :#{canonize(method)}"
275
- send method, args, block
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