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