fumbler 0.0.1
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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +98 -0
- data/Rakefile +2 -0
- data/fumbler.gemspec +25 -0
- data/lib/fumbler.rb +9 -0
- data/lib/fumbler/engine.rb +16 -0
- data/lib/fumbler/filter.rb +45 -0
- data/lib/fumbler/model.rb +41 -0
- data/lib/fumbler/parser.rb +86 -0
- data/lib/fumbler/template.rb +8 -0
- data/lib/fumbler/version.rb +3 -0
- data/spec/fumbler_model_spec.rb +44 -0
- data/spec/fumbler_parser_spec.rb +51 -0
- data/spec/fumbler_templater_spec.rb +69 -0
- metadata +105 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
Fumbler
|
2
|
+
=======
|
3
|
+
|
4
|
+
This is the start of a ruby template engine based on the Tumblr syntax.
|
5
|
+
|
6
|
+
It's not production ready, and this is my first gem so please try it out and let me know if I'm doing anything wrong.
|
7
|
+
|
8
|
+
Some better examples are coming, checkout the specs for basic usage.
|
9
|
+
|
10
|
+
|
11
|
+
Overview
|
12
|
+
--------
|
13
|
+
|
14
|
+
The aim is to create a safe-evaluating template engine based on the designer friendly Tumblr syntax. It will be a lot more restrictive than ERB and even Liquid, but slightly more evaluating than Mustache.
|
15
|
+
|
16
|
+
It will enable you to give the designer limited control flow, safely evaluating contexts, nest-able blocks, and a few extensions to make things easier.
|
17
|
+
|
18
|
+
|
19
|
+
Whats Implemented
|
20
|
+
-----------------
|
21
|
+
|
22
|
+
|
23
|
+
###Model
|
24
|
+
|
25
|
+
Inherit from the Model class to create your context which the template can access, it includes a little attr_reader style helper called 'fumbleable' to make stuff available to the template so you can apply it to existing classes and not worry about giving access to db saves etc.
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
class Cage < Fumbler::Model
|
30
|
+
fumbleable :inside,:current
|
31
|
+
|
32
|
+
def initialize(c)
|
33
|
+
@current = c
|
34
|
+
end
|
35
|
+
|
36
|
+
def inside
|
37
|
+
"im trapped"
|
38
|
+
end
|
39
|
+
|
40
|
+
def current
|
41
|
+
@current
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Context < Fumbler::Model
|
46
|
+
|
47
|
+
fumbleable :you, :cage, :cages
|
48
|
+
|
49
|
+
def you
|
50
|
+
"dave"
|
51
|
+
end
|
52
|
+
|
53
|
+
def hidden
|
54
|
+
"you cant access me"
|
55
|
+
end
|
56
|
+
|
57
|
+
def cage
|
58
|
+
Cage.new(0)
|
59
|
+
end
|
60
|
+
|
61
|
+
def cages
|
62
|
+
[Cage.new(1),Cage.new(2)]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
@context = Context.new
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
###Template
|
70
|
+
|
71
|
+
This is based on [Tilt](https://github.com/rtomayko/tilt) but not everything is implemented yet.
|
72
|
+
|
73
|
+
The current syntax supports basic {tags} and {block:items}{tagsinparent}or{tagsinhere}{/block:items}, blocks can be nested and will always look to the parent for missing tags.
|
74
|
+
|
75
|
+
t = Fumbler::Template.new {"hello {you}, {block:cage}{current}{/block:cage} {block:cages}{you}{current},{/block:cages}]"}
|
76
|
+
t.render(@context)
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
TODO
|
81
|
+
----
|
82
|
+
|
83
|
+
* Attributes
|
84
|
+
* Meta-settings
|
85
|
+
* Partials
|
86
|
+
* Layout Inheritance
|
87
|
+
* File handling
|
88
|
+
* Rails Integration via Tilt
|
89
|
+
* Re-write the regex as a token scanner
|
90
|
+
* Lots More!
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
Acknowledgements
|
95
|
+
----------------
|
96
|
+
|
97
|
+
This is based on the [Temple](https://github.com/judofyr/temple) framework, taking a few tips from [Mustache](https://github.com/defunkt/mustache). The syntax aims to resemble that of [Tumblr](http://www.tumblr.com) and (Posterous)[http://www.posterous.com].
|
98
|
+
|
data/Rakefile
ADDED
data/fumbler.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "fumbler/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "fumbler"
|
7
|
+
s.version = Fumbler::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Anthony Corcutt"]
|
10
|
+
s.email = ["acorcutt@me.com"]
|
11
|
+
s.homepage = "https://github.com/acorcutt/fumbler"
|
12
|
+
s.summary = %q{Tumblr style template engine for ruby}
|
13
|
+
|
14
|
+
s.rubyforge_project = "fumbler"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency("temple")
|
22
|
+
s.add_dependency("tilt")
|
23
|
+
|
24
|
+
s.add_development_dependency("rspec", ["~> 2.4"])
|
25
|
+
end
|
data/lib/fumbler.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'temple'
|
2
|
+
require 'fumbler'
|
3
|
+
|
4
|
+
module Fumbler
|
5
|
+
class Engine < Temple::Engine
|
6
|
+
use Fumbler::Parser
|
7
|
+
use Fumbler::Filter
|
8
|
+
|
9
|
+
#filter :EscapeHTML, :use_html_safe
|
10
|
+
filter :MultiFlattener
|
11
|
+
filter :StaticMerger
|
12
|
+
filter :DynamicInliner
|
13
|
+
|
14
|
+
generator :ArrayBuffer
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'temple'
|
2
|
+
|
3
|
+
module Fumbler
|
4
|
+
#
|
5
|
+
# We just take our array and turn it into something Temple understands
|
6
|
+
#
|
7
|
+
# We prefix any calls with fumble_ which will be defined in our context class, and any children
|
8
|
+
#
|
9
|
+
#
|
10
|
+
class Filter < Temple::Filter
|
11
|
+
def on_multi(*exps)
|
12
|
+
exps.each_with_index do |exp,i|
|
13
|
+
name = exp[1]
|
14
|
+
case exp[0].to_sym
|
15
|
+
when :dynamic
|
16
|
+
exps[i] = [:dynamic,"fumble_#{name}"]
|
17
|
+
when :block
|
18
|
+
if exp[1] == "end"
|
19
|
+
#just strip any attributes and double up end tags to match block
|
20
|
+
exps[i] = [:block,"end;end"]
|
21
|
+
else
|
22
|
+
exps[i]=[:static,"block"]
|
23
|
+
|
24
|
+
# TODO - attributes, first we need to fix the parser to grab the whole attribute including quotes, also allow fumble_*params
|
25
|
+
atr = exp[2..-1]
|
26
|
+
|
27
|
+
# TODO - handle Arrays - think we just need to add it and also end;end above? or inject :multi
|
28
|
+
exps[i]= [:block,<<-code]
|
29
|
+
c = #{name}
|
30
|
+
c = [c] unless c.is_a?(Array)
|
31
|
+
c.each do |b|
|
32
|
+
b.fumble(self) do
|
33
|
+
code
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
return [:multi, *exps]
|
38
|
+
end
|
39
|
+
|
40
|
+
# Create evaluating string
|
41
|
+
def ev(s)
|
42
|
+
"#\{#{s}}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Fumbler
|
2
|
+
|
3
|
+
class Model
|
4
|
+
|
5
|
+
def self.fumbleable(*accessors)
|
6
|
+
accessors.each do |m|
|
7
|
+
class_eval <<-EOS
|
8
|
+
def fumble_#{m}
|
9
|
+
self.#{m}
|
10
|
+
end
|
11
|
+
EOS
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# What I'm trying todo is make blocks work inside blocks, and still be able to access
|
16
|
+
# the parents attributes, instance_eval lets us do something similar to javascripts with(o){}
|
17
|
+
# In this example we cant access 'you' inside the cage context how we would like to
|
18
|
+
# as its not a local, but see how 'outside' works. So we need to catch the missing_method
|
19
|
+
# and push send up to the parent, which might be a bit slow but it simplifies the block filter.
|
20
|
+
#
|
21
|
+
# @context.fumble(self){
|
22
|
+
# puts you #defined in root context class
|
23
|
+
# outside = "outside"
|
24
|
+
# cage.fumble(self){
|
25
|
+
# puts outside
|
26
|
+
# puts inside #defined in cage class
|
27
|
+
# puts you #this errors unless we catch method_missing
|
28
|
+
# }
|
29
|
+
# }
|
30
|
+
def fumble(parent,&block)
|
31
|
+
@parent = parent
|
32
|
+
instance_eval &block
|
33
|
+
end
|
34
|
+
|
35
|
+
def method_missing(sym, *args,&block)
|
36
|
+
if @parent
|
37
|
+
@parent.send(sym, *args,&block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'temple'
|
2
|
+
|
3
|
+
module Fumbler
|
4
|
+
#
|
5
|
+
# Handles parsing of our template string
|
6
|
+
#
|
7
|
+
# The Basics:
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# Display something:
|
11
|
+
#
|
12
|
+
# {title}
|
13
|
+
#
|
14
|
+
# Blocks:
|
15
|
+
#
|
16
|
+
# {block:item limit="10"}
|
17
|
+
# {title}
|
18
|
+
# {/block:item}
|
19
|
+
#
|
20
|
+
#
|
21
|
+
# We allow a few tag formats and special html style wrapper to hide from rich html editors
|
22
|
+
# {block:items} {{block:items}} <{block:items}> <!--{block:items}--> are all equivelant,
|
23
|
+
# The surrounding tag will always be stripped from the output.
|
24
|
+
#
|
25
|
+
# Escape things with
|
26
|
+
# {{{ <{im}> {escaped} .css{color:red} }}}
|
27
|
+
#
|
28
|
+
# TODO - make tag patterns customizable so we can do ${tag} etc.
|
29
|
+
# TODO - combine the block and tag pattern, then allow tag & block delimiters to be differerent e.g. erb style
|
30
|
+
# TODO - or switch to scanning for opening and closing tags so we can do things like {block:tag a="{" b="}"} and ignore {tag}}
|
31
|
+
|
32
|
+
class Parser
|
33
|
+
include Temple::Mixins::Options
|
34
|
+
|
35
|
+
TAG_PATTERN = /{{{(.*?)}}}|({|{{|<{|<!--{)\s*?(\/?\b.+?)\s*?(}-->|}>|}}|})/m #order of the { {{ <{ <!--{ tag groups is important
|
36
|
+
|
37
|
+
BLOCK_PATTERN = /(\/?\b\w+\b)\s*?:\s*?(\b\w+\b)\s*?(.*)/m
|
38
|
+
|
39
|
+
ATTRIBUTE_PATTERN = /\s+(\b\w+\b)\s*=\s*(?:(['"])(.*?)\2)/m #a='1' b="2"
|
40
|
+
|
41
|
+
def compile(input)
|
42
|
+
result = [:multi]
|
43
|
+
return result unless input
|
44
|
+
|
45
|
+
pos = 0
|
46
|
+
blocks = 0
|
47
|
+
input.scan(TAG_PATTERN) do |escaped,s, tag, e|
|
48
|
+
m = Regexp.last_match
|
49
|
+
text = input[pos...m.begin(0)]
|
50
|
+
pos = m.end(0)
|
51
|
+
result << [:static, text] if !text.empty?
|
52
|
+
if escaped
|
53
|
+
result << [:static, escaped]
|
54
|
+
else
|
55
|
+
m = tag.match(BLOCK_PATTERN)
|
56
|
+
if m
|
57
|
+
t = m[2]
|
58
|
+
a = []
|
59
|
+
m[3].scan(ATTRIBUTE_PATTERN) do |key,q,value|
|
60
|
+
a << [key,value]
|
61
|
+
end
|
62
|
+
case m[1]
|
63
|
+
when "block"
|
64
|
+
result << [:block,t,a]
|
65
|
+
blocks+=1
|
66
|
+
when "/block"
|
67
|
+
result << [:block,"end"]
|
68
|
+
blocks-=1
|
69
|
+
end
|
70
|
+
else
|
71
|
+
result << [:dynamic,tag]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
text = input[pos..-1]
|
76
|
+
result << [:static, text] if !text.empty?
|
77
|
+
|
78
|
+
#close any blocks left over
|
79
|
+
blocks.times do
|
80
|
+
result << [:block,"end"]
|
81
|
+
end
|
82
|
+
|
83
|
+
result
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'fumbler/model'
|
2
|
+
|
3
|
+
describe Fumbler::Model do
|
4
|
+
before(:all) do
|
5
|
+
|
6
|
+
class Context < Fumbler::Model
|
7
|
+
|
8
|
+
fumbleable :you, :cage
|
9
|
+
|
10
|
+
def you
|
11
|
+
"dave"
|
12
|
+
end
|
13
|
+
|
14
|
+
class Cage < Fumbler::Model
|
15
|
+
fumbleable :inside
|
16
|
+
|
17
|
+
def inside
|
18
|
+
"im trapped"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def cage
|
23
|
+
Cage.new
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should find all attributes" do
|
31
|
+
@context = Context.new
|
32
|
+
|
33
|
+
@context.fumble(self){
|
34
|
+
you.inspect
|
35
|
+
outside = "outside"
|
36
|
+
cage.fumble(self){
|
37
|
+
outside.inspect
|
38
|
+
inside.inspect
|
39
|
+
you.inspect
|
40
|
+
}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'fumbler/engine'
|
2
|
+
require 'fumbler/parser'
|
3
|
+
|
4
|
+
describe Fumbler::Engine do
|
5
|
+
it "should make a new temple engine" do
|
6
|
+
Fumbler::Engine.new
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Fumbler::Parser do
|
11
|
+
it "should make a new parser" do
|
12
|
+
Fumbler::Parser.new
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should parse empty string" do
|
16
|
+
Fumbler::Parser.new.compile("").should eql([:multi])
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should parse some static text" do
|
20
|
+
Fumbler::Parser.new.compile("some text").should eql([:multi,[:static,"some text"]])
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should parse escaped tags" do
|
24
|
+
Fumbler::Parser.new.compile("hello {{{ <{im}> {escaped} .css{color:red} }}}").should eql([:multi,[:static,"hello "],[:static," <{im}> {escaped} .css{color:red} "]])
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should parse a text tag" do
|
28
|
+
Fumbler::Parser.new.compile("hello {name}-{ age }").should eql([:multi,[:static,"hello "],[:dynamic,"name"],[:static,"-"],[:dynamic,"age"]])
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should parse a text tag across multi-lines" do
|
32
|
+
Fumbler::Parser.new.compile("hello {name\nhere}").should eql([:multi,[:static,"hello "],[:dynamic, "name\nhere"]])
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should parse a text tag in all tag formats" do
|
36
|
+
Fumbler::Parser.new.compile("hello {a}{{b}}<{c}><!--{d}-->").should eql([:multi,[:static,"hello "],[:dynamic,"a"],[:dynamic,"b"],[:dynamic,"c"],[:dynamic,"d"]])
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should parse a block tag" do
|
40
|
+
Fumbler::Parser.new.compile("hello {block:item}{name}{/block:item}").should eql([:multi,[:static,"hello "],[:block,"item",[]],[:dynamic,"name"],[:block,"end"]])
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should parse a spaced block tag" do
|
44
|
+
Fumbler::Parser.new.compile("hello { block : item}{name}{/block : item }").should eql([:multi,[:static,"hello "],[:block,"item",[]],[:dynamic,"name"],[:block,"end"]])
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should parse a block tag with attributes" do
|
48
|
+
Fumbler::Parser.new.compile("hello {block:item a=\"1\" b='2'}{name}{/block:item}").should eql([:multi,[:static,"hello "],[:block,"item",[["a","1"],["b","2"]]],[:dynamic,"name"],[:block,"end"]])
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'fumbler/template'
|
2
|
+
require 'fumbler/model'
|
3
|
+
|
4
|
+
describe Fumbler::Template do
|
5
|
+
before(:all) do
|
6
|
+
class Context < Fumbler::Model
|
7
|
+
|
8
|
+
fumbleable :you, :cage, :cages
|
9
|
+
|
10
|
+
def you
|
11
|
+
"dave"
|
12
|
+
end
|
13
|
+
|
14
|
+
def hidden
|
15
|
+
"you cant access me"
|
16
|
+
end
|
17
|
+
|
18
|
+
class Cage < Fumbler::Model
|
19
|
+
fumbleable :inside,:current
|
20
|
+
|
21
|
+
def initialize(c)
|
22
|
+
@current = c
|
23
|
+
end
|
24
|
+
|
25
|
+
def inside
|
26
|
+
"im trapped"
|
27
|
+
end
|
28
|
+
|
29
|
+
def current
|
30
|
+
@current
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def cage
|
35
|
+
Cage.new(0)
|
36
|
+
end
|
37
|
+
|
38
|
+
def cages
|
39
|
+
[Cage.new(1),Cage.new(2)]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
@context = Context.new
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should make a new temple" do
|
47
|
+
Fumbler::Template.new {}
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should render some static text" do
|
51
|
+
Fumbler::Template.new{"hello from template"}.render.should eql("hello from template")
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should render a tag" do
|
55
|
+
t = Fumbler::Template.new {"hello {you}"}
|
56
|
+
t.render(@context).should eql("hello dave")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should render a block" do
|
60
|
+
t = Fumbler::Template.new {"hello {you}, {block:cage}{you} {inside}{/block:cage}"}
|
61
|
+
t.render(@context).should eql("hello dave, dave im trapped")
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should render a block a few times" do
|
65
|
+
t = Fumbler::Template.new {"hello {you}, [{block:cages}{you}{current},{/block:cages}]"}
|
66
|
+
t.render(@context).should eql("hello dave, [dave1,dave2,]")
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fumbler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Anthony Corcutt
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-03-06 00:00:00 +00:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: temple
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: tilt
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0"
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: rspec
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "2.4"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
description:
|
50
|
+
email:
|
51
|
+
- acorcutt@me.com
|
52
|
+
executables: []
|
53
|
+
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files: []
|
57
|
+
|
58
|
+
files:
|
59
|
+
- .gitignore
|
60
|
+
- Gemfile
|
61
|
+
- README.md
|
62
|
+
- Rakefile
|
63
|
+
- fumbler.gemspec
|
64
|
+
- lib/fumbler.rb
|
65
|
+
- lib/fumbler/engine.rb
|
66
|
+
- lib/fumbler/filter.rb
|
67
|
+
- lib/fumbler/model.rb
|
68
|
+
- lib/fumbler/parser.rb
|
69
|
+
- lib/fumbler/template.rb
|
70
|
+
- lib/fumbler/version.rb
|
71
|
+
- spec/fumbler_model_spec.rb
|
72
|
+
- spec/fumbler_parser_spec.rb
|
73
|
+
- spec/fumbler_templater_spec.rb
|
74
|
+
has_rdoc: true
|
75
|
+
homepage: https://github.com/acorcutt/fumbler
|
76
|
+
licenses: []
|
77
|
+
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: "0"
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: "0"
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project: fumbler
|
98
|
+
rubygems_version: 1.6.1
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: Tumblr style template engine for ruby
|
102
|
+
test_files:
|
103
|
+
- spec/fumbler_model_spec.rb
|
104
|
+
- spec/fumbler_parser_spec.rb
|
105
|
+
- spec/fumbler_templater_spec.rb
|