marker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,153 @@
1
+ #--
2
+ # Copyright 2009 Ryan Blue.
3
+ # Distributed under the terms of the GNU General Public License (GPL).
4
+ # See the LICENSE file for further information on the GPL.
5
+ #++
6
+
7
+ require 'marker/common'
8
+
9
+ module Marker #:nodoc:
10
+ class InternalLink < ParseNode
11
+ def to_html( options = {} )
12
+ "<a href='#{path(options)}'>#{label(:html, options)}</a>"
13
+ end
14
+
15
+ def to_s( options = {} )
16
+ f = options[:footnotes]
17
+ if f
18
+ l = label(:text, options)
19
+ n = f.add( path(options), l )
20
+ "#{l} [#{n}]"
21
+ else
22
+ "#{label(:text, options)} [#{path}]"
23
+ end
24
+ end
25
+
26
+ def path( options = {} )
27
+ p = options[:link_base] || ''
28
+ p.chomp! '/'
29
+ p += '/' + target
30
+ end
31
+
32
+ def label( format, options = {} )
33
+ if l
34
+ case format
35
+ when :html
36
+ l.to_html(options)
37
+ else
38
+ l.to_s(options)
39
+ end
40
+ else
41
+ if a
42
+ # an arg delimiter was present, but without a label
43
+ # sanitize: remove trailing parenthetical remarks
44
+ target.gsub(/\s*\([^)]*\)$/, '')
45
+ else
46
+ target
47
+ end
48
+ end
49
+ end
50
+
51
+ def target
52
+ if t
53
+ t.text_value
54
+ else
55
+ ''
56
+ end
57
+ end
58
+
59
+ #-- defaults ++
60
+ def t #:nodoc:
61
+ nil
62
+ end
63
+
64
+ def a #:nodoc:
65
+ nil
66
+ end
67
+
68
+ def l #:nodoc:
69
+ nil
70
+ end
71
+ end
72
+
73
+ class ExternalLink < ParseNode
74
+ def to_html( options = {} )
75
+ if l
76
+ "<a href='#{target}'>#{label(:html, options)}</a>"
77
+ else
78
+ f = options[:footnotes]
79
+ if f
80
+ n = f.add( target )
81
+ "<a href='#{target}'>[#{n}]</a>"
82
+ else
83
+ "<a href='#{target}'></a>"
84
+ end
85
+ end
86
+ end
87
+
88
+ def to_s( options = {} )
89
+ f = options[:footnotes]
90
+ if l
91
+ if f
92
+ n = f.add( target, label(:text, options) )
93
+ "#{label(:text, options)} [#{n}]"
94
+ else
95
+ "#{label(:text, options)} [#{target}]"
96
+ end
97
+ else
98
+ if f
99
+ n = f.add( target )
100
+ "[#{n}]"
101
+ else
102
+ target
103
+ end
104
+ end
105
+ end
106
+
107
+ def label( format, options = {} )
108
+ if l
109
+ case format
110
+ when :html
111
+ l.to_html(options)
112
+ else
113
+ l.to_s(options)
114
+ end
115
+ else
116
+ ''
117
+ end
118
+ end
119
+
120
+ def target
121
+ if t
122
+ t.text_value
123
+ else
124
+ ''
125
+ end
126
+ end
127
+
128
+ #-- defaults ++
129
+ def t #:nodoc:
130
+ nil
131
+ end
132
+
133
+ def l #:nodoc:
134
+ nil
135
+ end
136
+ end
137
+
138
+ class URL < ParseNode
139
+ # TODO: these should output links just like "[url]". The link tags
140
+ # shouldn't call these methods, these are called when the URL is not in a
141
+ # link. The link templates should grab the URL themselves.
142
+ def to_html( options = {} )
143
+ text_value
144
+ end
145
+
146
+ def to_s( options = {} )
147
+ text_value
148
+ end
149
+ end
150
+
151
+ class Protocol < ParseNode
152
+ end
153
+ end
@@ -0,0 +1,188 @@
1
+ #--
2
+ # Copyright 2009 Ryan Blue.
3
+ # Distributed under the terms of the GNU General Public License (GPL).
4
+ # See the LICENSE file for further information on the GPL.
5
+ #++
6
+
7
+ require 'marker/common'
8
+
9
+ module Marker #:nodoc:
10
+ # used to collect list lines into lists structured hierarchically, like in HTML
11
+ class ListBuilder
12
+ attr_reader :tag, :contents, :attrs
13
+
14
+ def initialize( contents, tag, attrs = {} )
15
+ @contents = [contents].flatten
16
+ @tag = tag
17
+ @attrs = attrs
18
+ end
19
+
20
+ # returns true if the l has the same tag
21
+ def ===( l )
22
+ ( l.is_a? self.class and tag == l.tag )
23
+ end
24
+
25
+ def <<( l )
26
+ last = contents.last
27
+
28
+ if last and last === l
29
+ last += l
30
+ else
31
+ contents << l
32
+ end
33
+
34
+ self
35
+ end
36
+
37
+ def +( l )
38
+ l.contents.each { |i| self << i } if self === l
39
+
40
+ self
41
+ end
42
+
43
+ def to_html( options = {} )
44
+ if tag
45
+ "<#{tag}" +
46
+ ( attrs.any?? ' ' : '' ) +
47
+ attrs.map { |k, v|
48
+ "#{k}='#{v}'"
49
+ }.join(' ') +
50
+ ">" +
51
+ contents.map { |i|
52
+ i.to_html(options)
53
+ }.join +
54
+ "</#{tag}>"
55
+ else
56
+ contents.map { |i|
57
+ i.to_html(options)
58
+ }.join
59
+ end
60
+ end
61
+
62
+ def to_s( options = {} )
63
+ strs = []
64
+ contents.each_with_index { |i, ind|
65
+ strs << i.to_s( options.merge(
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
82
+
83
+ def to_s( options = {} )
84
+ l = ListBuilder.new( [], nil )
85
+ to_a.each do |item|
86
+ l << item.structure
87
+ end
88
+ l.to_s(options)
89
+ end
90
+ end
91
+
92
+ class Bulleted < ParseNode
93
+ def to_html( options = {} )
94
+ "<li>#{phrase.to_html(options)}</li>"
95
+ end
96
+
97
+ def to_s( options = {} )
98
+ indent = (options[:indent] || 0)
99
+ ' ' * (indent > 0 ? indent - 1 : 0) +
100
+ ' * ' + phrase.to_s( options )
101
+ end
102
+
103
+ def structure
104
+ if phrase
105
+ ListBuilder.new( self, :ul )
106
+ else
107
+ ListBuilder.new( list_item.structure, :ul )
108
+ end
109
+ end
110
+
111
+ #-- defaults ++
112
+ def phrase
113
+ nil
114
+ end
115
+ end
116
+
117
+ class Numbered < ParseNode
118
+ def to_html( options = {} )
119
+ "<li>#{phrase.to_html(options)}</li>"
120
+ end
121
+
122
+ def to_s( options = {} )
123
+ indent = (options[:indent] || 0)
124
+ ' ' * (indent > 0 ? indent - 1 : 0) +
125
+ "#{'%2d' % options[:num]}. #{phrase.to_s( options )}"
126
+ end
127
+
128
+ def structure
129
+ if phrase
130
+ ListBuilder.new( self, :ol )
131
+ else
132
+ ListBuilder.new( list_item.structure, :ol )
133
+ end
134
+ end
135
+
136
+ #-- defaults ++
137
+ def phrase
138
+ nil
139
+ end
140
+ end
141
+
142
+ class Indented < ParseNode
143
+ def to_html( options = {} )
144
+ "<div>#{phrase.to_html(options)}</div>"
145
+ end
146
+
147
+ def to_s( options = {} )
148
+ indent = (options[:indent] || 0)
149
+ ' ' * (indent > 0 ? indent : 0) +
150
+ phrase.to_s(options)
151
+ end
152
+
153
+ def structure
154
+ if phrase
155
+ ListBuilder.new( self, :div, :class => 'indent' )
156
+ else
157
+ ListBuilder.new( list_item.structure, :div, :class => 'indent' )
158
+ end
159
+ end
160
+
161
+ #-- defaults ++
162
+ def phrase
163
+ nil
164
+ end
165
+ end
166
+
167
+ class Definition < ParseNode
168
+ def to_html( options = {} )
169
+ "<dt>#{term.to_html(options)}</dt>" +
170
+ ( definition ? "<dd>#{definition.to_html(options)}</dd>" : "" )
171
+ end
172
+
173
+ def to_s( options = {} )
174
+ indent = (options[:indent] || 0)
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 )
181
+ end
182
+
183
+ #-- defaults ++
184
+ def definition
185
+ nil
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,81 @@
1
+ #--
2
+ # Copyright 2009 Ryan Blue.
3
+ # Distributed under the terms of the GNU General Public License (GPL).
4
+ # See the LICENSE file for further information on the GPL.
5
+ #++
6
+
7
+ require 'marker/common'
8
+
9
+ module Marker #:nodoc:
10
+ class Markup < RecursiveList
11
+ def to_html( options = {} )
12
+ options = make_options( options )
13
+
14
+ [
15
+ to_a.map{ |b|
16
+ b.to_html(options)
17
+ }, options[:footnotes].to_html( options )
18
+ ].flatten.join("\n")
19
+ end
20
+
21
+ def to_s( options = {} )
22
+ options = make_options( options )
23
+
24
+ [
25
+ to_a.map{ |b|
26
+ b.to_s(options)
27
+ }, options[:footnotes].to_s( options )
28
+ ].flatten.join("\n")
29
+ end
30
+
31
+ def make_options( user_options )
32
+ o = Marker.render_options.dup
33
+ o.merge!( :link_base => Marker.link_base )
34
+ o.merge!( :footnotes => Footnotes.new ) unless user_options[:nofootnotes]
35
+ o.merge!( user_options )
36
+ o
37
+ end
38
+ end
39
+
40
+ class Footnotes
41
+ def notes
42
+ @notes ||= []
43
+ end
44
+
45
+ def add( *args )
46
+ notes << args
47
+ notes.size
48
+ end
49
+
50
+ def to_html( options = {} )
51
+ return "" unless notes.any?
52
+
53
+ "<ol>" +
54
+ notes.map { |n|
55
+ target = n.shift
56
+ if n.any?
57
+ "<li><a href='#{target}'>#{n.join(' ')}</a></li>"
58
+ else
59
+ "<li><a href='#{target}'>#{target}</a></li>"
60
+ end
61
+ }.join +
62
+ "</ol>"
63
+ end
64
+
65
+ def to_s( options = {} )
66
+ return "" unless notes.any?
67
+
68
+ s = "\n"
69
+ notes.each_with_index{ |n, i|
70
+ target = n.shift
71
+ if n.any?
72
+ s << "#{'%2d' % (i + 1)}. #{n.join(' ')}: #{target}\n"
73
+ else
74
+ s << "#{'%2d' % (i + 1)}. #{target}\n"
75
+ end
76
+ }
77
+
78
+ s
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,105 @@
1
+ #--
2
+ # Copyright 2009 Ryan Blue.
3
+ # Distributed under the terms of the GNU General Public License (GPL).
4
+ # See the LICENSE file for further information on the GPL.
5
+ #++
6
+
7
+ require 'marker/common'
8
+
9
+ module Marker #:nodoc:
10
+ class Template < ParseNode
11
+ def to_html( options = {} )
12
+ render( :html, options )
13
+ end
14
+
15
+ def to_s( options = {} )
16
+ render( :text, options )
17
+ end
18
+
19
+ def render( format, options = {} )
20
+ Marker.templates.send( target, format, *arg_list( format, options ) )
21
+ end
22
+
23
+ def target
24
+ # sanitize the string to get a method name
25
+ t.text_value.gsub(/\s/, '_').to_sym
26
+ end
27
+
28
+ def arg_list( format, options )
29
+ ( args ? args.to_arg_list( format, options ) : [[], {}] )
30
+ end
31
+
32
+ #-- defaults ++
33
+ def t #:nodoc:
34
+ nil
35
+ end
36
+
37
+ def args #:nodoc:
38
+ nil
39
+ end
40
+ end
41
+
42
+ class Arguments < RecursiveList
43
+ def to_arg_list( format, options = {} )
44
+ pos_params = []
45
+ named_params = {}
46
+
47
+ case format
48
+ when :html
49
+ to_a.each do |a|
50
+ next unless a
51
+ if a.name
52
+ named_params[a.name.to_html( options )] = a.val.to_html( options )
53
+ else
54
+ pos_params << a.val.to_html( options )
55
+ end
56
+ end
57
+ else
58
+ to_a.each do |a|
59
+ next unless a
60
+ if a.name
61
+ named_params[a.name.to_s( options )] = a.val.to_s( options )
62
+ else
63
+ pos_params << a.val.to_s( options )
64
+ end
65
+ end
66
+ end
67
+
68
+ [pos_params, named_params]
69
+ end
70
+
71
+ def to_html( options = {} )
72
+ to_a.map { |a|
73
+ a ? a.to_html(options) : ''
74
+ }.join(', ')
75
+ end
76
+
77
+ def to_s( options = {} )
78
+ to_a.map { |a|
79
+ a ? a.to_s(options) : ''
80
+ }.join(', ')
81
+ end
82
+ end
83
+
84
+ class Argument < ParseNode
85
+ def to_html( options = {} )
86
+ to_s
87
+ end
88
+
89
+ def to_s( options = {} )
90
+ ( name ? "'#{name}' => '#{val}'" : "'#{val}'" )
91
+ end
92
+
93
+ #-- defaults ++
94
+ def name #:nodoc:
95
+ nil
96
+ end
97
+ end
98
+
99
+ # A set of basic templates for rendering
100
+ module DefaultTemplates
101
+ def self.method_missing( sym, *args )
102
+ "render:#{sym}( #{args.map(&:inspect).join(', ')} )"
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,96 @@
1
+ #--
2
+ # Copyright 2009 Ryan Blue.
3
+ # Distributed under the terms of the GNU General Public License (GPL).
4
+ # See the LICENSE file for further information on the GPL.
5
+ #++
6
+
7
+ require 'marker/common'
8
+
9
+ module Marker #:nodoc:
10
+ class Paragraph < RecursiveList
11
+ def to_html( options = {} )
12
+ '<p>' +
13
+ to_a.map { |p|
14
+ p.to_html(options)
15
+ }.join(' ') +
16
+ '</p>'
17
+ end
18
+
19
+ # TODO: add wordwrap
20
+ def to_s( options = {} )
21
+ to_a.map { |p|
22
+ p.to_s(options)
23
+ }.join(' ')
24
+ end
25
+ end
26
+
27
+ class Phrase < RecursiveList
28
+ def to_html( options = {} )
29
+ s = h.to_html(options)
30
+ s << ' ' if space?
31
+ s << r.to_html(options) if r
32
+ s
33
+ end
34
+
35
+ def to_s( options = {} )
36
+ s = h.to_s(options)
37
+ s << ' ' if space?
38
+ s << r.to_s(options) if r
39
+ s
40
+ end
41
+
42
+ # returns true if there was white space after the first "word"
43
+ def space?
44
+ (ws and ws.present?) or (aws and aws.present?)
45
+ end
46
+
47
+ #-- defaults ++
48
+ def ws
49
+ nil
50
+ end
51
+
52
+ def aws
53
+ nil
54
+ end
55
+ end
56
+
57
+ class Word < ParseNode
58
+ def to_html( options = {} )
59
+ text_value
60
+ end
61
+
62
+ def to_s( options = {} )
63
+ text_value
64
+ end
65
+ end
66
+
67
+ class Delimiter < ParseNode
68
+ def to_html( options = {} )
69
+ text_value
70
+ end
71
+
72
+ def to_s( options = {} )
73
+ text_value
74
+ end
75
+ end
76
+
77
+ class Bold < ParseNode
78
+ def to_html( options = {} )
79
+ "<b>#{bold_enclosed_text.to_html(options)}</b>"
80
+ end
81
+
82
+ def to_s( options = {} )
83
+ "*#{bold_enclosed_text.to_s(options)}*"
84
+ end
85
+ end
86
+
87
+ class Italic < ParseNode
88
+ def to_html( options = {} )
89
+ "<i>#{italic_enclosed_text.to_html(options)}</i>"
90
+ end
91
+
92
+ def to_s( options = {} )
93
+ "/#{italic_enclosed_text.to_s(options)}/"
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,48 @@
1
+ #--
2
+ # Copyright 2009 Ryan Blue.
3
+ # Distributed under the terms of the GNU General Public License (GPL).
4
+ # See the LICENSE file for further information on the GPL.
5
+ #++
6
+
7
+ require 'marker/common'
8
+
9
+ module Marker #:nodoc:
10
+ class VerbatimArea < RecursiveList
11
+ def to_html( options = {} )
12
+ "<pre>\n" +
13
+ to_a.map { |l|
14
+ l.to_html(options)
15
+ }.join("\n") +
16
+ "\n</pre>"
17
+ end
18
+
19
+ def to_s( options = {} )
20
+ "-- \n" +
21
+ to_a.map { |l|
22
+ l.to_s(options)
23
+ }.join("\n") +
24
+ "\n-- "
25
+ end
26
+ end
27
+
28
+ class Verbatim < ParseNode
29
+ def to_html( options = {} )
30
+ v.text_value
31
+ end
32
+
33
+ def to_s( options = {} )
34
+ v.text_value
35
+ end
36
+ end
37
+
38
+ class HorizRule < ParseNode
39
+ def to_html( options = {} )
40
+ "<hr />"
41
+ end
42
+
43
+ def to_s( options = {} )
44
+ width = options[:width] || 80
45
+ "-" * width
46
+ end
47
+ end
48
+ end