faqml 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ faqml (0.1.2)
5
+ redcarpet (>= 2.1.1)
6
+ temple (>= 0.4.0)
7
+ tilt (~> 1.3.3)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ redcarpet (2.1.1)
13
+ temple (0.4.0)
14
+ tilt (1.3.3)
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ faqml!
data/faqml.gemspec CHANGED
@@ -1,15 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.dirname(__FILE__) + '/lib/fml/version'
3
+ require 'date'
4
+
1
5
  Gem::Specification.new do |s|
2
6
  s.name = 'faqml'
3
- s.version = '0.1.1'
4
- s.date = '2012-08-10'
7
+ s.version = FAQML::VERSION
8
+ s.date = Date.today.to_s
5
9
  s.summary = "FAQ Markup Language"
6
- s.description = "A Simple FAQ Markup Language, based on Markdown"
10
+ s.description = "A Simple FAQ Markup Language"
7
11
  s.authors = ["Eric Redmond"]
8
12
  s.email = 'eric@basho.com'
9
- s.files = ["lib/faqml.rb"]
10
13
  s.homepage = 'http://rubygems.org/gems/faqml'
11
14
 
12
15
  s.add_dependency('redcarpet', '>= 2.1.1')
16
+ s.add_dependency('temple', '>= 0.4.0')
17
+ s.add_dependency('tilt', '~> 1.3.3')
13
18
 
14
19
  s.files = `git ls-files`.split("\n")
15
20
  s.require_paths = ["lib"]
data/lib/faqml.rb CHANGED
@@ -1,63 +1,8 @@
1
+ # encoding: utf-8
1
2
  # FAQ Markup Language
2
- # require 'rubygems'
3
- require 'redcarpet'
4
3
 
5
- class FML
6
- def initialize(data)
7
- @data = data
8
- end
9
-
10
- def to_html(attrs={})
11
- linked_question = attrs[:linked_question] || true
12
-
13
- faqs, current = [], :t
14
- faqs << {:q => "", :a => "", :t => ""}
15
- @data.split(/\n/m).each do |line|
16
- # start an answer block
17
- if line =~ /^===\s*$/
18
- raise "Cannot begin an answer without a question title" if current != :q
19
- current = :a
20
- next
21
- end
22
-
23
- # start a new question block
24
- if line =~ /^---/
25
- line = line.sub(/^#/, '').strip
26
- faqs << {:q => "", :a => "", :t => ""}
27
- current = :t
28
- next
29
- end
30
-
31
- faqs.last[current] += line
32
-
33
- current = :q if current == :t && line.strip != ''
34
- end
35
-
36
- renderer = Redcarpet::Render::HTML.new
37
- extensions = {fenced_code_blocks: true}
38
- redcarpet = Redcarpet::Markdown.new(renderer, extensions)
39
-
40
- buffer = ""
41
- for faq in faqs
42
- next if faq[:t] == ''
43
- buffer += "<section class=\"qna\">\n"
44
- if linked_question
45
- buffer += "<h1><a href=\"#\">#{faq[:t].to_s.strip}</a></h1>\n"
46
- else
47
- buffer += "<h1>#{faq[:t].to_s.strip}</h1>\n"
48
- end
49
- buffer += "<div class=\"qna\">"
50
- if faq[:q].to_s != ''
51
- buffer += "<div class=\"question\">"
52
- buffer += redcarpet.render(faq[:q])
53
- buffer += "</div>"
54
- end
55
- buffer += "<div class=\"answer\">"
56
- buffer += redcarpet.render(faq[:a].to_s)
57
- buffer += "</div>"
58
- buffer += "</div>"
59
- buffer += "</section>\n"
60
- end
61
- return buffer
62
- end
63
- end
4
+ require 'temple'
5
+ require 'fml/version'
6
+ require 'fml/parser'
7
+ require 'fml/engine'
8
+ require 'fml/template'
data/lib/fml/engine.rb ADDED
@@ -0,0 +1,31 @@
1
+ class FAQML::Engine < Temple::Engine
2
+
3
+ set_default_options :pretty => false,
4
+ :sort_attrs => true,
5
+ :attr_wrapper => '"',
6
+ :attr_delimiter => {'class' => ' '},
7
+ :remove_empty_attrs => true,
8
+ :generator => Temple::Generators::ArrayBuffer
9
+ # :default_tag => 'div'
10
+
11
+ use FAQML::Parser, :strict
12
+
13
+ # TODO: replace inline generation with a markdown filter
14
+ # use FAQML::MarkdownFilter
15
+ # use FAQML::WrapFilter
16
+
17
+ html :AttributeMerger, :attr_delimiter
18
+ html :AttributeSorter, :sort_attrs
19
+ html :AttributeRemover, :remove_empty_attrs
20
+ html :Pretty, :format, :attr_wrapper, :pretty, :indent
21
+
22
+ filter :Escapable, :use_html_safe, :disable_escape
23
+ filter :MultiFlattener
24
+ # filter :StaticMerger
25
+ # filter :DynamicInliner
26
+
27
+ # generator :ArrayBuffer, :buffer
28
+
29
+ use(:Optimizer) { (options[:streaming] ? Temple::Filters::StaticMerger : Temple::Filters::DynamicInliner).new }
30
+ use(:Generator) { options[:generator].new(options) }
31
+ end
data/lib/fml/parser.rb ADDED
@@ -0,0 +1,148 @@
1
+ require 'redcarpet'
2
+
3
+ # Transforms FML into a Temple expression
4
+ # @api private
5
+ class FAQML::Parser
6
+ include Temple::Mixins::Options
7
+
8
+ set_default_options :tabsize => 4,
9
+ :encoding => 'utf-8'
10
+
11
+ class SyntaxError < StandardError
12
+ attr_reader :error, :file, :line, :lineno, :column
13
+
14
+ def initialize(error, file, line, lineno, column)
15
+ @error = error
16
+ @file = file || '(__TEMPLATE__)'
17
+ @line = line.to_s
18
+ @lineno = lineno
19
+ @column = column
20
+ end
21
+
22
+ def to_s
23
+ line = @line.strip
24
+ column = @column + line.size - @line.size
25
+ %{#{error}
26
+ #{file}, Line #{lineno}
27
+ #{line}
28
+ #{' ' * column}^
29
+ }
30
+ end
31
+ end
32
+
33
+ def initialize(options = {})
34
+ super
35
+
36
+ renderer = Redcarpet::Render::HTML.new
37
+ extensions = {fenced_code_blocks: true}
38
+ @markdown = Redcarpet::Markdown.new(renderer, extensions)
39
+
40
+ @tab = ' ' * @options[:tabsize]
41
+ end
42
+
43
+ # Compile string to Temple expression
44
+ #
45
+ # @param [String] str FML code
46
+ # @return [Array] Temple expression representing the code]]
47
+ def call(str)
48
+ # Set string encoding if option is set
49
+ if options[:encoding] && str.respond_to?(:encoding)
50
+ old_enc = str.encoding
51
+ str = str.dup if str.frozen?
52
+ str.force_encoding(options[:encoding])
53
+ # Fall back to old encoding if new encoding is invalid
54
+ str.force_encoding(old_enc) unless str.valid_encoding?
55
+ end
56
+
57
+ result = [:multi]
58
+ reset(str.split(/\r?\n/), result)
59
+
60
+ parse_line while next_line
61
+
62
+ reset
63
+ result
64
+ end
65
+
66
+ private
67
+
68
+ # TODO: the markdown rendering should be a filter... that way
69
+ # you could have different kinds of FML markups
70
+
71
+ # TODO: rewrite this to have a sort of wrapping filter... have this just output:
72
+ # [:question, [:summary, [text]], [:data, [line, line...]]]
73
+ # [:answer, [:summary, [text]], [:data, [line, line...]]]
74
+
75
+ def parse_line
76
+ # start an answer block
77
+ if @line =~ /^a(nswer)?(\s*)\:\s*(.*?)$/i
78
+ asummary = @line.sub(/^a(nswer)?(\s*)\:(\s*)/i, '')
79
+ syntax_error!("Cannot begin an answer without a question") if @current != :q
80
+ @current = :a
81
+
82
+ @stacks.last.last << [:html, :tag, 'details', [:html, :attrs, [:html, :attr, 'class', [:static, 'answer']]], [:multi]]
83
+ @stacks.last.last.last.last << [:html, :tag, 'summary', [:multi], [:static, asummary]]
84
+ @stacks.last.last.last.last << [:html, :tag, 'div', [:multi], [:multi]]
85
+
86
+ elsif @line =~ /^q(uestion)?(\s*)\:\s*(.*?)$/i
87
+ qsummary = @line.sub(/^q(uestion)?(\s*)\:(\s*)/i, '')
88
+ @current = :q
89
+
90
+ @stacks << [:html, :tag, 'section', [:html, :attrs, [:html, :attr, 'class', [:static, 'qna']]],[:multi]]
91
+ @stacks.last.last << [:html, :tag, 'details', [:html, :attrs, [:html, :attr, 'class', [:static, 'question']]], [:multi]]
92
+ @stacks.last.last.last.last << [:html, :tag, 'summary', [:multi], [:static, qsummary]]
93
+ @stacks.last.last.last.last << [:html, :tag, 'div', [:multi], [:multi]]
94
+
95
+ else
96
+ indent = get_indent(@line)
97
+ if @base_indent == 0
98
+ @base_indent = indent
99
+ @strip_exp = %r"^\s{#{@base_indent}}"
100
+ end
101
+
102
+ if indent >= 1
103
+ # strip off base_indent from @line
104
+ @stacks.last.last.last.last.last.last << [:static, @line.sub("\t", @tab).sub(@strip_exp, '')]
105
+ @stacks.last.last.last.last.last.last << [:newline]
106
+ else
107
+ # done with the indented block
108
+ @base_indent = 0
109
+ end
110
+
111
+ @current = :q if @line.strip != ''
112
+ end
113
+ end
114
+
115
+ def reset(lines = nil, stacks = nil)
116
+ @stacks = stacks
117
+ @base_indent = 0
118
+ @lineno = 0
119
+ @lines = lines
120
+ @line = @orig_line = nil
121
+ @current = nil
122
+ end
123
+
124
+ def next_line
125
+ if @lines.empty?
126
+ @orig_line = @line = nil
127
+ else
128
+ @orig_line = @lines.shift
129
+ @lineno += 1
130
+ @line = @orig_line.dup
131
+ end
132
+ end
133
+
134
+ def get_indent(line)
135
+ # Figure out the indentation. ugly/slow/ ripped from Slim
136
+ line[/\A[ \t]*/].sub("\t", @tab).size
137
+ end
138
+
139
+ # Helper for raising exceptions
140
+ def syntax_error!(message, args = {})
141
+ args[:orig_line] ||= @orig_line
142
+ args[:line] ||= @line
143
+ args[:lineno] ||= @lineno
144
+ args[:column] ||= args[:orig_line] && args[:line] ? args[:orig_line].size - args[:line].size : 0
145
+ raise SyntaxError.new(message, options[:file],
146
+ args[:orig_line], args[:lineno], args[:column])
147
+ end
148
+ end
@@ -0,0 +1,18 @@
1
+ module FAQML
2
+ # Tilt template implementation for FAQML
3
+ # @api public
4
+ Template = Temple::Templates::Tilt(FAQML::Engine, :register_as => :fml)
5
+
6
+ if Object.const_defined?(:Rails)
7
+ # Rails template implementation for FAQML
8
+ # @api public
9
+ RailsTemplate = Temple::Templates::Rails(FAQML::Engine,
10
+ :register_as => :fml,
11
+ # Use rails-specific generator. This is necessary
12
+ # to support block capturing and streaming.
13
+ :generator => Temple::Generators::RailsOutputBuffer,
14
+ # Rails takes care of the capturing by itself.
15
+ :disable_capture => true,
16
+ :streaming => Object.const_defined?(:Fiber))
17
+ end
18
+ end
@@ -0,0 +1,4 @@
1
+ module FAQML
2
+ # @api public
3
+ VERSION = '0.1.2'
4
+ end
data/test/test1.fml ADDED
@@ -0,0 +1,14 @@
1
+ question: What's the best bear?
2
+ What kind of bear is best?
3
+
4
+ answer: Blackbear
5
+ False. *Blackbear*
6
+
7
+ q: Do bears eat beats?
8
+
9
+ a: Bears. Beats. _Battlestar Galactica._
10
+
11
+ Q:
12
+ Do bears eat beats?
13
+ A:
14
+ Bears. Beats. Battlestar Galactica.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faqml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-10 00:00:00.000000000 Z
12
+ date: 2012-08-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redcarpet
@@ -27,16 +27,54 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: 2.1.1
30
- description: A Simple FAQ Markup Language, based on Markdown
30
+ - !ruby/object:Gem::Dependency
31
+ name: temple
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 0.4.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 0.4.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: tilt
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 1.3.3
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.3.3
62
+ description: A Simple FAQ Markup Language
31
63
  email: eric@basho.com
32
64
  executables: []
33
65
  extensions: []
34
66
  extra_rdoc_files: []
35
67
  files:
36
68
  - Gemfile
69
+ - Gemfile.lock
37
70
  - README.markdown
38
71
  - faqml.gemspec
39
72
  - lib/faqml.rb
73
+ - lib/fml/engine.rb
74
+ - lib/fml/parser.rb
75
+ - lib/fml/template.rb
76
+ - lib/fml/version.rb
77
+ - test/test1.fml
40
78
  homepage: http://rubygems.org/gems/faqml
41
79
  licenses: []
42
80
  post_install_message: