marker 0.3.3 → 0.4.0
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/README +26 -20
- data/lib/marker/common.rb +4 -0
- data/lib/marker/language.treetop +515 -78
- data/lib/marker/lists.rb +142 -112
- data/lib/marker/markup.rb +34 -16
- data/lib/marker/templates.rb +51 -4
- data/lib/marker/text.rb +37 -5
- data/test/encodings_test.rb +3 -3
- data/test/formatting_test.rb +1 -1
- data/test/helper.rb +9 -0
- data/test/lists_test.rb +12 -5
- data/test/templates_test.rb +138 -23
- data/test/test_helper.rb +12 -1
- metadata +58 -59
data/lib/marker/lists.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright 2009 Ryan Blue.
|
2
|
+
# Copyright 2009-2012 Ryan Blue.
|
3
3
|
# Distributed under the terms of the GNU General Public License (GPL).
|
4
4
|
# See the LICENSE file for further information on the GPL.
|
5
5
|
#++
|
@@ -7,177 +7,206 @@
|
|
7
7
|
require 'marker/common'
|
8
8
|
|
9
9
|
module Marker #:nodoc:
|
10
|
-
# used to collect list lines into lists structured hierarchically, like in HTML
|
11
10
|
class ListBuilder
|
12
|
-
attr_reader :
|
11
|
+
attr_reader :type
|
12
|
+
attr_reader :items
|
13
13
|
|
14
|
-
def initialize(
|
15
|
-
@
|
16
|
-
@
|
17
|
-
@attrs = attrs
|
14
|
+
def initialize( type, item=nil )
|
15
|
+
@type = type
|
16
|
+
@items = (item ? [item] : [])
|
18
17
|
end
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
( l.is_a? self.class and tag == l.tag )
|
19
|
+
def can_merge?( other )
|
20
|
+
type == other.type
|
23
21
|
end
|
24
22
|
|
25
|
-
def
|
26
|
-
|
23
|
+
def merge!( list )
|
24
|
+
list.items.each { |item| add( item ) }
|
25
|
+
end
|
27
26
|
|
28
|
-
|
29
|
-
|
27
|
+
def add( item )
|
28
|
+
if items.last and items.last.can_merge? item
|
29
|
+
items.last.merge! item
|
30
30
|
else
|
31
|
-
|
31
|
+
items << item
|
32
32
|
end
|
33
|
-
|
34
|
-
self
|
35
33
|
end
|
36
34
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
self
|
35
|
+
def empty?
|
36
|
+
items.empty?
|
41
37
|
end
|
42
38
|
|
43
|
-
def to_html( options
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
}
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
}
|
54
|
-
"</#{tag}>"
|
39
|
+
def to_html( options={} )
|
40
|
+
inner_html = items.map { |item| item.to_html(options) }.join
|
41
|
+
case type
|
42
|
+
when :bulleted
|
43
|
+
"<ul>#{inner_html}</ul>"
|
44
|
+
when :numbered
|
45
|
+
"<ol>#{inner_html}</ol>"
|
46
|
+
when :indented
|
47
|
+
"<div class='indent'>#{inner_html}</div>"
|
48
|
+
when :definition
|
49
|
+
"<dl>#{inner_html}</dl>"
|
55
50
|
else
|
56
|
-
|
57
|
-
i.to_html(options)
|
58
|
-
}.join
|
51
|
+
inner_html
|
59
52
|
end
|
60
53
|
end
|
61
54
|
|
62
|
-
def to_s( options
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
:indent => ( options[:indent] || 0 ) + ( tag ? 1 : 0 ),
|
67
|
-
:num => ind + 1
|
68
|
-
) )
|
69
|
-
}
|
70
|
-
strs.join("\n")
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
class List < RecursiveList
|
75
|
-
def to_html( options = {} )
|
76
|
-
l = ListBuilder.new( [], nil )
|
77
|
-
to_a.each do |item|
|
78
|
-
l << item.structure
|
79
|
-
end
|
80
|
-
l.to_html(options)
|
81
|
-
end
|
55
|
+
def to_s( options={} )
|
56
|
+
indent = (options[:indent] ? options[:indent] + 1 : -1)
|
57
|
+
# sublists are already indented because they are part of an item.
|
58
|
+
indent -= 1 if type == :sublist
|
82
59
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
60
|
+
case type
|
61
|
+
when :numbered
|
62
|
+
items.each_with_index.map { |item, num|
|
63
|
+
item.to_s(options.merge(:indent => indent, :num => num))
|
64
|
+
}.join("\n")
|
65
|
+
else
|
66
|
+
items.map { |item|
|
67
|
+
item.to_s(options.merge(:indent => indent))
|
68
|
+
}.join("\n")
|
87
69
|
end
|
88
|
-
l.to_s(options)
|
89
70
|
end
|
90
71
|
end
|
91
72
|
|
92
|
-
class
|
93
|
-
|
94
|
-
|
73
|
+
class ItemBuilder
|
74
|
+
attr_reader :type
|
75
|
+
attr_reader :content
|
76
|
+
attr_reader :sublists
|
77
|
+
|
78
|
+
def initialize( type, content_or_sublist )
|
79
|
+
@type = type
|
80
|
+
|
81
|
+
if content_or_sublist.respond_to? :items
|
82
|
+
@content = nil
|
83
|
+
@sublists = ListBuilder.new(:sublist, content_or_sublist)
|
84
|
+
else
|
85
|
+
@content = content_or_sublist
|
86
|
+
@sublists = ListBuilder.new(:sublist)
|
87
|
+
end
|
95
88
|
end
|
96
89
|
|
97
|
-
def
|
98
|
-
|
99
|
-
|
100
|
-
|
90
|
+
def can_merge?( other )
|
91
|
+
other.content.nil?
|
92
|
+
end
|
93
|
+
|
94
|
+
def merge!( item )
|
95
|
+
sublists.merge! item.sublists
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_html( options={} )
|
99
|
+
case type
|
100
|
+
when :bulleted, :numbered
|
101
|
+
"<li>" +
|
102
|
+
( content ? content.to_html(options) : "" ) +
|
103
|
+
sublists.to_html(options) +
|
104
|
+
"</li>"
|
105
|
+
when :indented
|
106
|
+
"<div class='indented_item'>" +
|
107
|
+
( content ? content.to_html(options) : "" ) +
|
108
|
+
sublists.to_html(options) +
|
109
|
+
"</div>"
|
110
|
+
when :definition
|
111
|
+
if content
|
112
|
+
term, definition = content
|
113
|
+
"<dt>#{term.to_html(options)}</dt><dd>#{definition.to_html(options)}#{sublists.to_html(options)}</dd>"
|
114
|
+
else
|
115
|
+
"<dd>#{sublists.to_html(options)}</dd>"
|
116
|
+
end
|
117
|
+
end
|
101
118
|
end
|
102
119
|
|
103
|
-
def
|
104
|
-
if
|
105
|
-
|
120
|
+
def to_s( options={} )
|
121
|
+
if content
|
122
|
+
indent = ' ' * options[:indent]
|
123
|
+
item_str = case type
|
124
|
+
when :bulleted
|
125
|
+
' * ' + content.to_s(options)
|
126
|
+
when :numbered
|
127
|
+
"#{'%2d' % (options[:num]+1)}. " + content.to_s(options)
|
128
|
+
when :indented
|
129
|
+
' ' + content.to_s(options)
|
130
|
+
when :definition
|
131
|
+
term, definition = content
|
132
|
+
' ' + term.to_s(options) + ( definition ? ' :: ' + definition.to_s(options) : '' )
|
133
|
+
end
|
134
|
+
sublist_str = ( sublists.empty? ? '' : "\n#{sublists.to_s(options)}" )
|
135
|
+
"#{indent}#{item_str}#{sublist_str}"
|
106
136
|
else
|
107
|
-
|
137
|
+
sublists.to_s(options)
|
108
138
|
end
|
109
139
|
end
|
140
|
+
end
|
110
141
|
|
111
|
-
|
112
|
-
def
|
113
|
-
|
142
|
+
class List < RecursiveList
|
143
|
+
def builder
|
144
|
+
list_builder = ListBuilder.new(:root)
|
145
|
+
to_a.each do |node|
|
146
|
+
list_builder.add( node.builder )
|
147
|
+
end
|
148
|
+
list_builder
|
114
149
|
end
|
115
|
-
end
|
116
150
|
|
117
|
-
class Numbered < ParseNode
|
118
151
|
def to_html( options = {} )
|
119
|
-
|
152
|
+
builder.to_html(options)
|
120
153
|
end
|
121
154
|
|
122
155
|
def to_s( options = {} )
|
123
|
-
|
124
|
-
' ' * (indent > 0 ? indent - 1 : 0) +
|
125
|
-
"#{'%2d' % options[:num]}. #{phrase.to_s( options )}"
|
156
|
+
builder.to_s(options)
|
126
157
|
end
|
158
|
+
end
|
127
159
|
|
128
|
-
|
129
|
-
|
130
|
-
|
160
|
+
class ListNode < ParseNode
|
161
|
+
def builder
|
162
|
+
if content
|
163
|
+
ListBuilder.new( type, ItemBuilder.new( type, content ) )
|
131
164
|
else
|
132
|
-
ListBuilder.new(
|
165
|
+
ListBuilder.new( type, ItemBuilder.new( type, item.builder ) )
|
133
166
|
end
|
134
167
|
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class Bulleted < ListNode
|
171
|
+
def type
|
172
|
+
:bulleted
|
173
|
+
end
|
135
174
|
|
136
175
|
#-- defaults ++
|
137
|
-
def
|
176
|
+
def content
|
138
177
|
nil
|
139
178
|
end
|
140
179
|
end
|
141
180
|
|
142
|
-
class
|
143
|
-
def
|
144
|
-
|
181
|
+
class Numbered < ListNode
|
182
|
+
def type
|
183
|
+
:numbered
|
145
184
|
end
|
146
185
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
phrase.to_s(options)
|
186
|
+
#-- defaults ++
|
187
|
+
def content
|
188
|
+
nil
|
151
189
|
end
|
190
|
+
end
|
152
191
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
else
|
157
|
-
ListBuilder.new( list_item.structure, :div, :class => 'indent' )
|
158
|
-
end
|
192
|
+
class Indented < ListNode
|
193
|
+
def type
|
194
|
+
:indented
|
159
195
|
end
|
160
196
|
|
161
197
|
#-- defaults ++
|
162
|
-
def
|
198
|
+
def content
|
163
199
|
nil
|
164
200
|
end
|
165
201
|
end
|
166
202
|
|
167
|
-
class Definition <
|
168
|
-
def
|
169
|
-
|
170
|
-
( definition ? "<dd>#{definition.to_html(options)}</dd>" : "" )
|
203
|
+
class Definition < ListNode
|
204
|
+
def type
|
205
|
+
:definition
|
171
206
|
end
|
172
207
|
|
173
|
-
def
|
174
|
-
|
175
|
-
' ' * (indent > 0 ? indent - 1: 0) +
|
176
|
-
"#{term.to_s(options)} :: #{definition.to_s(options)}"
|
177
|
-
end
|
178
|
-
|
179
|
-
def structure
|
180
|
-
ListBuilder.new( self, :dl )
|
208
|
+
def content
|
209
|
+
[term, definition]
|
181
210
|
end
|
182
211
|
|
183
212
|
#-- defaults ++
|
@@ -186,3 +215,4 @@ module Marker #:nodoc:
|
|
186
215
|
end
|
187
216
|
end
|
188
217
|
end
|
218
|
+
|
data/lib/marker/markup.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright 2009 Ryan Blue.
|
2
|
+
# Copyright 2009-2012 Ryan Blue.
|
3
3
|
# Distributed under the terms of the GNU General Public License (GPL).
|
4
4
|
# See the LICENSE file for further information on the GPL.
|
5
5
|
#++
|
@@ -7,25 +7,24 @@
|
|
7
7
|
require 'marker/common'
|
8
8
|
|
9
9
|
module Marker #:nodoc:
|
10
|
-
class
|
10
|
+
class Document < ParseNode
|
11
11
|
def to_html( options = {} )
|
12
12
|
options = make_options( options )
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
].flatten.join("\n")
|
14
|
+
markup ? (
|
15
|
+
markup.to_html( options ) + "\n" +
|
16
|
+
options[:footnotes].to_html( options )
|
17
|
+
) : ""
|
19
18
|
end
|
20
19
|
|
21
20
|
def to_s( options = {} )
|
22
21
|
options = make_options( options )
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
|
24
|
+
markup ? (
|
25
|
+
markup.to_s( options ) + "\n\n" +
|
26
|
+
options[:footnotes].to_s( options )
|
27
|
+
) : ""
|
29
28
|
end
|
30
29
|
|
31
30
|
def make_options( user_options )
|
@@ -35,6 +34,25 @@ module Marker #:nodoc:
|
|
35
34
|
o.merge!( user_options )
|
36
35
|
o
|
37
36
|
end
|
37
|
+
|
38
|
+
#-- defaults ++
|
39
|
+
def markup
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Markup < RecursiveList
|
45
|
+
def to_html( options = {} )
|
46
|
+
to_a.map{ |b|
|
47
|
+
b.to_html(options)
|
48
|
+
}.join("\n")
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s( options = {} )
|
52
|
+
to_a.map{ |b|
|
53
|
+
b.to_s(options)
|
54
|
+
}.join("\n\n")
|
55
|
+
end
|
38
56
|
end
|
39
57
|
|
40
58
|
class Footnotes
|
@@ -65,11 +83,11 @@ module Marker #:nodoc:
|
|
65
83
|
def to_s( options = {} )
|
66
84
|
return "" unless notes.any?
|
67
85
|
|
68
|
-
s = "\n"
|
86
|
+
s = "\n---- Notes ----\n"
|
69
87
|
notes.each_with_index{ |n, i|
|
70
|
-
target = n
|
71
|
-
if
|
72
|
-
s << "#{'%2d' % (i + 1)}. #{
|
88
|
+
target, *label_words = n
|
89
|
+
if label_words.any?
|
90
|
+
s << "#{'%2d' % (i + 1)}. #{label_words.join(' ')}: #{target}\n"
|
73
91
|
else
|
74
92
|
s << "#{'%2d' % (i + 1)}. #{target}\n"
|
75
93
|
end
|
data/lib/marker/templates.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright 2009 Ryan Blue.
|
2
|
+
# Copyright 2009-2011 Ryan Blue.
|
3
3
|
# Distributed under the terms of the GNU General Public License (GPL).
|
4
4
|
# See the LICENSE file for further information on the GPL.
|
5
5
|
#++
|
@@ -9,7 +9,16 @@ require 'marker/common'
|
|
9
9
|
module Marker #:nodoc:
|
10
10
|
class Template < ParseNode
|
11
11
|
def to_html( options = {} )
|
12
|
-
|
12
|
+
# if this template contains block-style arguments, then it needs to be
|
13
|
+
# wrapped in a div. otherwise, all arguments are inline and it does not
|
14
|
+
# get wrapped. the template target is used as the html class.
|
15
|
+
#
|
16
|
+
# it may be a good idea to wrap inline templates in a span
|
17
|
+
if block?
|
18
|
+
"<div class='#{target}'>#{render( :html, options )}</div>"
|
19
|
+
else
|
20
|
+
render( :html, options )
|
21
|
+
end
|
13
22
|
end
|
14
23
|
|
15
24
|
def to_s( options = {} )
|
@@ -17,7 +26,13 @@ module Marker #:nodoc:
|
|
17
26
|
end
|
18
27
|
|
19
28
|
def render( format, options = {} )
|
20
|
-
|
29
|
+
# optionally change the format for argument rendering
|
30
|
+
if options[:template_formats] and options[:template_formats][target]
|
31
|
+
format = options[:template_formats][target]
|
32
|
+
end
|
33
|
+
|
34
|
+
ordered, named = arg_list( format, options )
|
35
|
+
Marker.templates.send( target, format, ordered, named, options )
|
21
36
|
end
|
22
37
|
|
23
38
|
def target
|
@@ -29,6 +44,10 @@ module Marker #:nodoc:
|
|
29
44
|
( args ? args.to_arg_list( format, options ) : [[], {}] )
|
30
45
|
end
|
31
46
|
|
47
|
+
def block?
|
48
|
+
( args ? args.block? : false )
|
49
|
+
end
|
50
|
+
|
32
51
|
#-- defaults ++
|
33
52
|
def t #:nodoc:
|
34
53
|
nil
|
@@ -45,6 +64,12 @@ module Marker #:nodoc:
|
|
45
64
|
named_params = {}
|
46
65
|
|
47
66
|
case format
|
67
|
+
when :raw
|
68
|
+
# don't render the text, just return the original value
|
69
|
+
# this is needed for special templates, like syntax highlighting
|
70
|
+
to_a.each do |a|
|
71
|
+
pos_params << a.text_value if a
|
72
|
+
end
|
48
73
|
when :html
|
49
74
|
to_a.each do |a|
|
50
75
|
next unless a
|
@@ -70,6 +95,12 @@ module Marker #:nodoc:
|
|
70
95
|
[pos_params, named_params]
|
71
96
|
end
|
72
97
|
|
98
|
+
# returns true if there are any block-style arguments and false if all
|
99
|
+
# arguments are inline-style
|
100
|
+
def block?
|
101
|
+
to_a.map(&:block?).reduce { |a, b| a or b }
|
102
|
+
end
|
103
|
+
|
73
104
|
def to_html( options = {} )
|
74
105
|
to_a.map { |a|
|
75
106
|
a ? a.to_html(options) : ''
|
@@ -85,13 +116,18 @@ module Marker #:nodoc:
|
|
85
116
|
|
86
117
|
class Argument < ParseNode
|
87
118
|
def to_html( options = {} )
|
88
|
-
to_s
|
119
|
+
to_s(options)
|
89
120
|
end
|
90
121
|
|
91
122
|
def to_s( options = {} )
|
92
123
|
( name ? "'#{name}' => '#{val}'" : "'#{val}'" )
|
93
124
|
end
|
94
125
|
|
126
|
+
# is this argument a block style?
|
127
|
+
def block?
|
128
|
+
true
|
129
|
+
end
|
130
|
+
|
95
131
|
#-- defaults ++
|
96
132
|
def name #:nodoc:
|
97
133
|
nil
|
@@ -102,6 +138,17 @@ module Marker #:nodoc:
|
|
102
138
|
end
|
103
139
|
end
|
104
140
|
|
141
|
+
# allow the grammar to distinguish between argument styles, but they render
|
142
|
+
# no differently at the argument level. these allow a template to decide
|
143
|
+
# whether it needs to be wrapped in a div for html output.
|
144
|
+
class InlineArgument < Argument
|
145
|
+
def block?
|
146
|
+
false
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class BlockArgument < Argument; end
|
151
|
+
|
105
152
|
# A set of basic templates for rendering
|
106
153
|
module DefaultTemplates
|
107
154
|
def self.method_missing( sym, *args )
|