faqml 0.1.1 → 0.1.2

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.
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: