marker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,98 @@
1
+ == Marker
2
+
3
+ Marker is a markup language parser designed for two needs:
4
+ # Need to mimic MediaWiki syntax
5
+ # Need to provide multiple output formats
6
+
7
+ Mimicing MediaWiki syntax is not exact. One reason is that the MediaWiki
8
+ parser itself is very complicated and handles many cases specially. It would
9
+ be very difficult to exactly copy the MediaWiki parser and it probably wouldn't
10
+ be worth the time because MediaWiki is intended for a wiki and needs to be
11
+ adapted to be used as a markup lanaguage--especially for multiple output
12
+ formats. The purpose of mimicing MediaWiki syntax is so that users don't have
13
+ to learn more than one markup language, so the implementation doesn't *need* to
14
+ be exact anyway.
15
+
16
+ Marker differs from MediaWiki in several ways, because it is a grammar-based
17
+ implementation. The grammar is written as a
18
+ Treetop[http://treetop.rubyforge.org/] parsing expression grammar (PEG).
19
+
20
+ Not implemented:
21
+ # Table of contents
22
+ # Tables
23
+
24
+ == Use
25
+
26
+ Parsing is done with either Marker.parse or Marker.parse_file. Both parse
27
+ methods will return a parse tree that has to_html and to_s methods that
28
+ "render" the markup. Both render methods will accept an options hash.
29
+
30
+ Example:
31
+ >> require 'marker'
32
+ => true
33
+ >> m = Marker.parse "== heading ==\nparagraph with '''bold''' text"
34
+ => Markup+...
35
+ >> puts m.to_s
36
+ heading
37
+ --------------------------------------------------------------------------------
38
+ paragraph with *bold* text
39
+ => nil
40
+ >> puts m.to_html
41
+ <h2>heading</h2>
42
+ <p>paragraph with <b>bold</b> text</p>
43
+ => nil
44
+
45
+ === Templates
46
+
47
+ Templates are implemented as method calls to a templates module. Each method
48
+ in the templates module is considered a template and can be called using the
49
+ "{{ name }}" syntax. Each template method is expected to take three arguments:
50
+ the render format (:html or :text), an array of positional parameters, and a
51
+ hash of named parameters. For example,
52
+ module MyTemplates
53
+ def logo( format, pos_params, name_params )
54
+ case format
55
+ when :html
56
+ '<img src="/images/logo.png" />'
57
+ else
58
+ ''
59
+ end
60
+ end
61
+ end
62
+
63
+ Template modules are passed to Marker by setting the +templates+ property:
64
+ require 'my_templates'
65
+ require 'marker'
66
+
67
+ Marker.templates = Templates
68
+
69
+ If no template method is found, the template call is printed for debugging:
70
+ >> puts Marker.parse( '{{t|one|two|name=val}}' ).to_s
71
+ render:t( :text, ["one", "two"], {"name"=>"val"} )
72
+
73
+ === Internal Links
74
+
75
+ Internal links are implemented as links with default prefixes. The link prefix
76
+ is specified by setting the +link_base+ property:
77
+ require 'marker'
78
+
79
+ Marker.link_base = 'http://example.com/pages/'
80
+
81
+ >> puts Marker.parse( '[[target|name]]' ).to_html
82
+ <p><a href='http://example.com/pages/target'>name</a></p>
83
+
84
+ The link target is appended to the link prefix, along with a beginning '/'. If
85
+ no link base is given, links are just the link target with a beginning '/'.
86
+ The link base can also be given as a render option.
87
+
88
+ === Unlabelled Links
89
+
90
+ (write me)
91
+
92
+ == Command Line Program
93
+
94
+ == License
95
+
96
+ Marker is copyright 2009 Ryan Blue and distributed under the terms of the GNU
97
+ General Public License (GPL). See the LICENSE file for further information on
98
+ the GPL, or visit http://creativecommons.org/licenses/GPL/2.0/.
data/bin/marker ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'ostruct'
5
+ require 'rubygems'
6
+
7
+ begin
8
+ require 'marker'
9
+ rescue LoadError
10
+ $: << File.join( File.dirname(__FILE__), '..', 'lib' )
11
+ require 'marker'
12
+ end
13
+
14
+ options = OpenStruct.new
15
+ options.format = :text
16
+ OptionParser.new do |opts|
17
+ opts.on( '--format FORMAT', [:text, :html],
18
+ 'Specify the output format (text, html)' ) do |format|
19
+ options.format = format
20
+ end
21
+ opts.on_tail('-h', '--help', 'Show this message') do
22
+ puts opts
23
+ exit
24
+ end
25
+ end.parse!
26
+
27
+ files = {}
28
+
29
+ if ARGV.empty? or ARGV.include? '-'
30
+ s = ''
31
+ # the parser expects a full block of text, grab it all
32
+ $stdin.each_line { |l| s << l }
33
+ files[:stdin] = Marker.parse( s )
34
+ end
35
+
36
+ ARGV.each do |f|
37
+ next if f == '-'
38
+ files[f] = Marker.parse_file( f )
39
+ end
40
+
41
+ if files.size > 1
42
+ files.each do |f, t|
43
+ puts "\n==> #{f} <=="
44
+ case options.format
45
+ when :html
46
+ puts t.to_html
47
+ else
48
+ puts t
49
+ end
50
+ end
51
+ else
52
+ # only one, so leave out the file name
53
+ case options.format
54
+ when :html
55
+ puts files.values.first.to_html
56
+ else
57
+ puts files.values.first
58
+ end
59
+ end
@@ -0,0 +1,40 @@
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 'treetop'
8
+
9
+ module Treetop #:nodoc:
10
+ module Runtime #:nodoc:
11
+ class SyntaxNode #:nodoc:
12
+ # returns whether the ParseNode matched any text
13
+ def present?
14
+ text_value.any?
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ module Marker #:nodoc:
21
+ # used to add methods to all parse nodes.
22
+ class ParseNode < Treetop::Runtime::SyntaxNode
23
+ end
24
+
25
+ # implements collection methods on a list using a recursive grammar definition
26
+ # requires defining +h+ and +r+
27
+ class RecursiveList < ParseNode
28
+ def to_a
29
+ if r
30
+ [h] + r.to_a
31
+ else
32
+ [h]
33
+ end
34
+ end
35
+
36
+ def r
37
+ nil
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,79 @@
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 Heading < ParseNode
11
+ # HTML-rendered headings, using <h#> tags.
12
+ def to_html( options = {} )
13
+ # find out how deep it is
14
+ d = [s.text_value.size, e.text_value.size].min
15
+ sn = s.text_value.size - d
16
+ en = e.text_value.size - d
17
+ if sn > 0
18
+ "<h#{d}>#{'=' * sn} #{label( :html, options )}</h#{d}>"
19
+ elsif en > 0
20
+ "<h#{d}>#{label( :html, options )} #{'=' * en}</h#{d}>"
21
+ else
22
+ "<h#{d}>#{label( :html, options )}</h#{d}>"
23
+ end
24
+ end
25
+
26
+ # Text-rendered headings. Should look like this:
27
+ #
28
+ # Heading Level 1
29
+ # ==========================================================================
30
+ #
31
+ # Heading Level 2
32
+ # --------------------------------------------------------------------------
33
+ #
34
+ # - Heading Level 3 --------------------------------------------------------
35
+ #
36
+ # --- Heading Level 4 ------------------------------------------------------
37
+ #
38
+ def to_s( options = {} )
39
+ width = options[:width] || 80
40
+ d = [s.text_value.size, e.text_value.size].min
41
+ sn = s.text_value.size - d
42
+ en = e.text_value.size - d
43
+
44
+ l = if sn > 0
45
+ "#{'=' * sn} #{label( :text, options )}"
46
+ elsif en > 0
47
+ "#{label( :text, options )} #{'=' * en}"
48
+ else
49
+ label( :text, options )
50
+ end
51
+
52
+ case d
53
+ when 1
54
+ "#{l}\n" + ('=' * width)
55
+ when 2
56
+ "#{l}\n" + ('-' * width)
57
+ else
58
+ l = " #{l} "
59
+ h = '-'*width
60
+ h[2*(d-3)+1, l.size] = l # slice substitution
61
+ h
62
+ end
63
+ end
64
+
65
+ def label( format, options = {} )
66
+ case format
67
+ when :html
68
+ l.to_html( options )
69
+ else
70
+ l.to_s( options )
71
+ end
72
+ end
73
+
74
+ #-- defaults ++
75
+ def l #:nodoc:
76
+ nil
77
+ end
78
+ end
79
+ end