marker 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 :tag, :contents, :attrs
11
+ attr_reader :type
12
+ attr_reader :items
13
13
 
14
- def initialize( contents, tag, attrs = {} )
15
- @contents = [contents].flatten
16
- @tag = tag
17
- @attrs = attrs
14
+ def initialize( type, item=nil )
15
+ @type = type
16
+ @items = (item ? [item] : [])
18
17
  end
19
18
 
20
- # returns true if the l has the same tag
21
- def ===( l )
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 <<( l )
26
- last = contents.last
23
+ def merge!( list )
24
+ list.items.each { |item| add( item ) }
25
+ end
27
26
 
28
- if last and last === l
29
- last += l
27
+ def add( item )
28
+ if items.last and items.last.can_merge? item
29
+ items.last.merge! item
30
30
  else
31
- contents << l
31
+ items << item
32
32
  end
33
-
34
- self
35
33
  end
36
34
 
37
- def +( l )
38
- l.contents.each { |i| self << i } if self === l
39
-
40
- self
35
+ def empty?
36
+ items.empty?
41
37
  end
42
38
 
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}>"
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
- contents.map { |i|
57
- i.to_html(options)
58
- }.join
51
+ inner_html
59
52
  end
60
53
  end
61
54
 
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
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
- def to_s( options = {} )
84
- l = ListBuilder.new( [], nil )
85
- to_a.each do |item|
86
- l << item.structure
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 Bulleted < ParseNode
93
- def to_html( options = {} )
94
- "<li>#{phrase.to_html(options)}</li>"
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 to_s( options = {} )
98
- indent = (options[:indent] || 0)
99
- ' ' * (indent > 0 ? indent - 1 : 0) +
100
- ' * ' + phrase.to_s( options )
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 structure
104
- if phrase
105
- ListBuilder.new( self, :ul )
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
- ListBuilder.new( list_item.structure, :ul )
137
+ sublists.to_s(options)
108
138
  end
109
139
  end
140
+ end
110
141
 
111
- #-- defaults ++
112
- def phrase
113
- nil
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
- "<li>#{phrase.to_html(options)}</li>"
152
+ builder.to_html(options)
120
153
  end
121
154
 
122
155
  def to_s( options = {} )
123
- indent = (options[:indent] || 0)
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
- def structure
129
- if phrase
130
- ListBuilder.new( self, :ol )
160
+ class ListNode < ParseNode
161
+ def builder
162
+ if content
163
+ ListBuilder.new( type, ItemBuilder.new( type, content ) )
131
164
  else
132
- ListBuilder.new( list_item.structure, :ol )
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 phrase
176
+ def content
138
177
  nil
139
178
  end
140
179
  end
141
180
 
142
- class Indented < ParseNode
143
- def to_html( options = {} )
144
- "<div>#{phrase.to_html(options)}</div>"
181
+ class Numbered < ListNode
182
+ def type
183
+ :numbered
145
184
  end
146
185
 
147
- def to_s( options = {} )
148
- indent = (options[:indent] || 0)
149
- ' ' * (indent > 0 ? indent : 0) +
150
- phrase.to_s(options)
186
+ #-- defaults ++
187
+ def content
188
+ nil
151
189
  end
190
+ end
152
191
 
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
192
+ class Indented < ListNode
193
+ def type
194
+ :indented
159
195
  end
160
196
 
161
197
  #-- defaults ++
162
- def phrase
198
+ def content
163
199
  nil
164
200
  end
165
201
  end
166
202
 
167
- class Definition < ParseNode
168
- def to_html( options = {} )
169
- "<dt>#{term.to_html(options)}</dt>" +
170
- ( definition ? "<dd>#{definition.to_html(options)}</dd>" : "" )
203
+ class Definition < ListNode
204
+ def type
205
+ :definition
171
206
  end
172
207
 
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 )
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
+
@@ -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 Markup < RecursiveList
10
+ class Document < ParseNode
11
11
  def to_html( options = {} )
12
12
  options = make_options( options )
13
13
 
14
- [
15
- to_a.map{ |b|
16
- b.to_html(options)
17
- }, options[:footnotes].to_html( options )
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
- to_a.map{ |b|
26
- b.to_s(options)
27
- }, options[:footnotes].to_s( options )
28
- ].flatten.join("\n")
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.shift
71
- if n.any?
72
- s << "#{'%2d' % (i + 1)}. #{n.join(' ')}: #{target}\n"
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
@@ -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
- render( :html, options )
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
- Marker.templates.send( target, format, *arg_list( format, options ) )
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 )