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.
@@ -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 )