braai 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.log
2
+ .DS_Store
3
+ doc
4
+ tmp
5
+ pkg
6
+ *.gem
7
+ *.pid
8
+ coverage
9
+ coverage.data
10
+ build/*
11
+ *.pbxuser
12
+ *.mode1v3
13
+ .svn
14
+ profile
15
+ .console_history
16
+ .sass-cache/*
17
+ .rake_tasks~
18
+ *.log.lck
19
+ solr/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in braai.gemspec
4
+ gemspec
5
+
6
+ gem "rspec"
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ braai (0.0.1)
5
+ activesupport
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (3.2.8)
11
+ i18n (~> 0.6)
12
+ multi_json (~> 1.0)
13
+ diff-lcs (1.1.3)
14
+ i18n (0.6.0)
15
+ multi_json (1.3.6)
16
+ rspec (2.11.0)
17
+ rspec-core (~> 2.11.0)
18
+ rspec-expectations (~> 2.11.0)
19
+ rspec-mocks (~> 2.11.0)
20
+ rspec-core (2.11.1)
21
+ rspec-expectations (2.11.2)
22
+ diff-lcs (~> 1.1.3)
23
+ rspec-mocks (2.11.2)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ braai!
30
+ rspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Mark Bates
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # Braai
2
+
3
+ A fully extensible templating system. Sick and tired of all of those templating systems that force you to do things their way? Yeah, me too! Thankfully there's Braai.
4
+ Braai let's you write your own Regular Expression matchers and then do whatever you'd like when the template is parsed! Sounds fun, doesn't it?
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'braai'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install braai
19
+
20
+ ## Usage
21
+
22
+ ### Built-in Matchers
23
+
24
+ Braai comes shipped with two simple matchers for you, but you can easily add your own.
25
+
26
+ The first matcher is a simple <code>to_s</code> handler. It will match a single variable and then call <code>to_s</code> on it:
27
+
28
+ <pre><code>
29
+ template = "Hi {{ name }}!"
30
+ response = Braai::Template.new(template).render(name: "Mark")
31
+ response # => "Hi Mark!"
32
+ </code></pre>
33
+
34
+ The second matcher will call a method on the variable.
35
+
36
+ <pre><code>
37
+ template = "Hi {{ name.upcase }}!"
38
+ response = Braai::Template.new(template).render(name: "Mark")
39
+ response # => "Hi MARK!"
40
+ </code></pre>
41
+
42
+ ### Custom Matchers
43
+
44
+ Braai let's you easily define your own matchers to do whatever you would like to do.
45
+
46
+ <pre><code>
47
+ template = "I'm {{ name }} and {{ mmm... bbq }}!"
48
+ Braai::Template.map(/mmm\.\.\. bbq/i) do |template, key, matches|
49
+ "Damn, I love BBQ!"
50
+ end
51
+
52
+ Braai::Template.map(/name/i) do |template, key, matches|
53
+ template.attributes[matches.first].upcase
54
+ end
55
+
56
+ Braai::Template.new(template).render # => "I'm MARK and Damn, I love BBQ!!"
57
+ </code></pre>
58
+
59
+ ### For Loops
60
+
61
+ Braai supports looping right out of the box.
62
+
63
+ <pre><code>
64
+ template = <<-EOF
65
+ &lt;h1>{{ greet }}&lt;/h1>
66
+ &lt;ul>
67
+ {{ for product in products }}
68
+ &lt;li>{{ product }}&lt;/li>
69
+ {{ /for }}
70
+ &lt;/ul>
71
+ &lt;div>
72
+ {{ for food in foods }}
73
+ &lt;p>{{ food }}&lt;/p>
74
+ {{ /for }}
75
+ &lt;/div>
76
+ &lt;h2>{{greet.upcase}}&lt;/h2>
77
+ EOF
78
+
79
+ Braai::Template.new(template).render(greet: "mark", products: %w{car boat truck}, foods: %w{apple orange})
80
+ # =>
81
+ "&lt;h1>mark&lt;/h1>
82
+ &lt;ul>
83
+ &lt;li>car&lt;/li>
84
+ &lt;li>boat&lt;/li>
85
+ &lt;li>truck&lt;/li>
86
+ &lt;/ul>
87
+ &lt;div>
88
+ &lt;p>apple&lt;/p>
89
+ &lt;p>orange&lt;/p>
90
+ &lt;/div>
91
+ &lt;h2>MARK&lt;/h2>"
92
+ </code></pre>
93
+
94
+ ## Contributing
95
+
96
+ 1. Fork it
97
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
98
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
99
+ 4. Push to the branch (`git push origin my-new-feature`)
100
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ desc "Run tests"
5
+ task :default do
6
+ system "bundle exec rspec"
7
+ end
data/braai.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'braai/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "braai"
8
+ gem.version = Braai::VERSION
9
+ gem.authors = ["Mark Bates"]
10
+ gem.email = ["mark@markbates.com"]
11
+ gem.description = %q{Fully extensible templating system.}
12
+ gem.summary = %q{Fully extensible templating system.}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency("activesupport")
21
+
22
+ end
@@ -0,0 +1,26 @@
1
+ class Braai::Configuration
2
+
3
+ attr_accessor :logger
4
+ attr_accessor :raise_on_missing_handler
5
+ attr_accessor :swallow_handler_errors
6
+ attr_accessor :for_loop_regex
7
+ attr_accessor :handler_regex
8
+
9
+ def initialize
10
+ self.raise_on_missing_handler = false
11
+ self.swallow_handler_errors = true
12
+ self.handler_regex = /{{\s*[^}]+\s*}}/i
13
+ self.for_loop_regex = /({{\s*for (\w+) in (\w+)\s*}}(.+?){{\s*\/for\s*}})/im
14
+ end
15
+
16
+ def logger
17
+ @logger ||= begin
18
+ if defined?(Rails)
19
+ Rails.logger
20
+ else
21
+ Logger.new(STDOUT)
22
+ end
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,66 @@
1
+ class Braai::Context
2
+
3
+ attr_accessor :attributes
4
+ attr_accessor :template
5
+ attr_accessor :handlers
6
+
7
+ def initialize(template, handlers, attributes = {})
8
+ self.attributes = HashWithIndifferentAccess.new(attributes)
9
+ self.template = template.dup
10
+ self.handlers = handlers
11
+ end
12
+
13
+ def render
14
+ begin
15
+ self.render!
16
+ rescue Exception => e
17
+ Braai.logger.error(e)
18
+ raise e
19
+ end
20
+ end
21
+
22
+ def render!
23
+ self.process_loops
24
+ self.process_keys
25
+ return self.template
26
+ end
27
+
28
+ protected
29
+ def process_loops
30
+ loops = self.template.scan(Braai.config.for_loop_regex)
31
+ loops.each do |loop|
32
+ res = []
33
+ self.attributes[loop[2]].each do |val|
34
+ res << Braai::Context.new(loop[3], self.handlers, self.attributes.merge(loop[1] => val)).render!
35
+ end
36
+ self.template.gsub!(loop[0], res.join("\n"))
37
+ end
38
+ end
39
+
40
+ def process_keys
41
+ keys = self.template.scan(Braai.config.handler_regex).flatten.uniq
42
+ keys.each do |key|
43
+ self.handle_key(key)
44
+ end
45
+ end
46
+
47
+ def handle_key(key)
48
+ stripped_key = key.gsub(/({|})/, "").strip
49
+ matched = false
50
+ self.handlers.each do |regex, handler|
51
+ regex = Regexp.new(regex)
52
+ if regex.match(stripped_key)
53
+ begin
54
+ val = handler.call(self, stripped_key, stripped_key.scan(regex).flatten)
55
+ self.template.gsub!(key, val.to_s) if val
56
+ rescue Exception => e
57
+ raise e unless Braai.config.swallow_handler_errors
58
+ end
59
+ matched = true
60
+ break
61
+ end
62
+ end
63
+ raise Braai::MissingHandlerError.new(stripped_key) if !matched && Braai.config.raise_on_missing_handler
64
+ end
65
+
66
+ end
@@ -0,0 +1,7 @@
1
+ module Braai
2
+ class MissingHandlerError < StandardError
3
+ def initialize(key)
4
+ super "#{key} was missing a handler! Please implement one."
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ module Braai::Handlers
2
+
3
+ def handlers
4
+ @handlers ||= reset!
5
+ end
6
+
7
+ def map(regex, &block)
8
+ @handlers = {regex.to_s => block}.merge(self.handlers)
9
+ end
10
+
11
+ def unmap(regex)
12
+ self.handlers.delete(regex.to_s)
13
+ end
14
+
15
+ def clear!
16
+ self.handlers.clear
17
+ end
18
+
19
+ def reset!
20
+ @handlers = {
21
+ /^([\w]+)\.([\w]+)$/i => ->(template, key, matches) {
22
+ attr = template.attributes[matches.first]
23
+ attr ? attr.send(matches.last) : nil
24
+ },
25
+ /^(\w+)$/i => ->(template, key, matches) {
26
+ attr = template.attributes[matches.first]
27
+ attr ? attr.to_s : nil
28
+ }
29
+ }
30
+ return @handlers
31
+ end
32
+
33
+ end
@@ -0,0 +1,27 @@
1
+ class Braai::Template
2
+ extend Braai::Handlers
3
+ include Braai::Handlers
4
+
5
+ attr_accessor :attributes
6
+ attr_accessor :template
7
+
8
+ def initialize(template, handlers = {})
9
+ self.template = template
10
+ @handlers = self.class.handlers.merge(handlers)
11
+ end
12
+
13
+ def render(attributes = {})
14
+ begin
15
+ return self.render!(attributes)
16
+ rescue Exception => e
17
+ Braai.logger.error(e)
18
+ raise e
19
+ end
20
+ end
21
+
22
+ def render!(attributes)
23
+ context = Braai::Context.new(self.template, self.handlers, attributes)
24
+ context.render!
25
+ end
26
+
27
+ end
@@ -0,0 +1,3 @@
1
+ module Braai
2
+ VERSION = "1.0.1"
3
+ end
data/lib/braai.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'logger'
2
+ require 'active_support/hash_with_indifferent_access'
3
+ require "braai/version"
4
+ require "braai/configuration"
5
+ require "braai/errors"
6
+ require "braai/handlers"
7
+ require "braai/template"
8
+ require "braai/context"
9
+
10
+ module Braai
11
+
12
+ class << self
13
+
14
+ def config
15
+ @config ||= Braai::Configuration.new
16
+ yield @config if block_given?
17
+ return @config
18
+ end
19
+
20
+ def logger
21
+ self.config.logger
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe Braai::Handlers do
4
+ include Braai::Handlers
5
+
6
+ describe 'map' do
7
+
8
+ it "maps a new handler" do
9
+ map("foo") {}
10
+ handlers.should include("foo")
11
+ end
12
+
13
+ it "makes the latest handler the first handler in the list" do
14
+ map("foo") {}
15
+ map("bar") {}
16
+ handlers.keys.first.should eql("bar")
17
+ end
18
+
19
+ end
20
+
21
+ describe 'unmap' do
22
+
23
+ it "unmaps a handler" do
24
+ map("foo") {}
25
+ handlers.should include("foo")
26
+ unmap("foo")
27
+ handlers.should_not include("foo")
28
+ end
29
+
30
+ end
31
+
32
+ describe 'clear!' do
33
+
34
+ it "removes all of the handlers" do
35
+ map("foo") {}
36
+ handlers.should_not be_empty
37
+ clear!
38
+ handlers.should be_empty
39
+ end
40
+
41
+ end
42
+
43
+ describe 'reset!' do
44
+
45
+ it "resets the handlers to their original state" do
46
+ handlers.should have(2).handlers
47
+ map("foo") {}
48
+ handlers.should have(3).handlers
49
+ reset!
50
+ handlers.should have(2).handlers
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,179 @@
1
+ require 'spec_helper'
2
+
3
+ describe Braai::Template do
4
+
5
+ let(:greet_regex) { /^greet$/i }
6
+ let(:greet_handler) do
7
+ ->(view, key, matches) {
8
+ view.attributes[:greet]
9
+ }
10
+ end
11
+
12
+ describe '.map' do
13
+
14
+ it "let's you register a handler" do
15
+ Braai::Template.handlers.should_not have_key(greet_regex.to_s)
16
+ Braai::Template.map(greet_regex, &greet_handler)
17
+ Braai::Template.handlers.should have_key(greet_regex.to_s)
18
+ end
19
+
20
+ end
21
+
22
+ describe '#render' do
23
+
24
+ before(:each) do
25
+ Braai::Template.map(greet_regex, &greet_handler)
26
+ end
27
+
28
+ it "renders a simple template" do
29
+ res = Braai::Template.new("{{ greet }}").render(greet: "Hi Mark")
30
+ res.should eql("Hi Mark")
31
+ end
32
+
33
+ it "doesn't care about spaces" do
34
+ template = "<h1>{{greet}}</h1><h2>{{ greet }}</h2>"
35
+ res = Braai::Template.new(template).render(greet: "Hi Mark")
36
+ res.should eql("<h1>Hi Mark</h1><h2>Hi Mark</h2>")
37
+ end
38
+
39
+ context "for loops" do
40
+
41
+ let(:template) do
42
+ <<-EOF
43
+ <h1>{{ greet }}</h1>
44
+ <ul>
45
+ {{ for product in products }}
46
+ <li>{{ product }}</li>
47
+ {{ /for }}
48
+ </ul>
49
+ <div>
50
+ {{ for food in foods }}
51
+ <p>{{ food }}</p>
52
+ {{ /for }}
53
+ </div>
54
+ <h2>{{greet.upcase}}</h2>
55
+ EOF
56
+ end
57
+
58
+ it "renders the loop" do
59
+ res = Braai::Template.new(template).render(greet: "mark", products: %w{car boat truck}, foods: %w{apple orange})
60
+ puts res
61
+ res.should match("<h1>mark</h1>")
62
+ res.should match("<li>car</li>")
63
+ res.should match("<li>boat</li>")
64
+ res.should match("<li>truck</li>")
65
+ res.should match("<p>apple</p>")
66
+ res.should match("<p>orange</p>")
67
+ res.should match("<h2>MARK</h2>")
68
+ end
69
+
70
+ # it "description" do
71
+ # template = "I'm {{ name }} and {{ mmm... bbq }}!"
72
+ # Braai::Template.map(/mmm\.\.\. bbq/i) do |template, key, matches|
73
+ # puts "key: #{key.inspect}"
74
+ # puts "matches: #{matches.inspect}"
75
+ # "Damn, I love BBQ!"
76
+ # end
77
+
78
+ # Braai::Template.map(/name/i) do |template, key, matches|
79
+ # template.attributes[matches.first].upcase
80
+ # end
81
+
82
+ # puts Braai::Template.new(template).render(name: "Mark")
83
+ # end
84
+
85
+ end
86
+
87
+ context "default handler" do
88
+
89
+ let(:template) { "{{ greet }} {{ name.upcase }}" }
90
+
91
+ it "uses the default handler to render" do
92
+ res = Braai::Template.new(template).render(greet: "Hi", name: "mark")
93
+ res.should eql("Hi MARK")
94
+ end
95
+
96
+ it "handles the attribute not being there" do
97
+ res = Braai::Template.new(template).render(greet: "Hi")
98
+ res.should eql("Hi {{ name.upcase }}")
99
+ end
100
+
101
+ end
102
+
103
+ context "missing handlers" do
104
+
105
+ before(:each) do
106
+ Braai::Template.reset!
107
+ end
108
+
109
+ after(:each) do
110
+ Braai.config.raise_on_missing_handler = false
111
+ end
112
+
113
+ context "raise_on_missing_handler is true" do
114
+
115
+ before(:each) do
116
+ Braai.config.raise_on_missing_handler = true
117
+ end
118
+
119
+ it "raises an error" do
120
+ expect {
121
+ Braai::Template.new("{{ please.greet.me }}").render(greet: "Hi Mark")
122
+ }.to raise_error(Braai::MissingHandlerError)
123
+ end
124
+
125
+ end
126
+
127
+ context "raise_on_missing_handler is false" do
128
+
129
+ it "does not raise an error" do
130
+ expect {
131
+ res = Braai::Template.new("{{ greet }}").render(greet: "Hi Mark")
132
+ res.should eql("{{ greet }}")
133
+ }.to_not raise_error(Braai::MissingHandlerError)
134
+ end
135
+
136
+ end
137
+
138
+ end
139
+
140
+ context "handler errors" do
141
+
142
+ before(:each) do
143
+ Braai::Template.map(/^foo$/) do |view, key, matches|
144
+ raise ArgumentError
145
+ end
146
+ end
147
+
148
+ let(:template) { "{{ foo }}" }
149
+
150
+ context "swallow_handler_errors is true" do
151
+
152
+ it "swallows errors in the handler" do
153
+ expect {
154
+ res = Braai::Template.new(template).render()
155
+ res.should eql template
156
+ }.to_not raise_error
157
+ end
158
+
159
+ end
160
+
161
+ context "swallow_handler_errors is false" do
162
+
163
+ before(:each) do
164
+ Braai.config.swallow_handler_errors = false
165
+ end
166
+
167
+ it "raises the errors from the handler" do
168
+ expect {
169
+ Braai::Template.new(template).render()
170
+ }.to raise_error(ArgumentError)
171
+ end
172
+
173
+ end
174
+
175
+ end
176
+
177
+ end
178
+
179
+ end
@@ -0,0 +1,13 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'braai' # and any other gems you need
4
+
5
+ Braai.config.logger = Logger.new(StringIO.new)
6
+
7
+ RSpec.configure do |config|
8
+
9
+ config.before do
10
+ Braai::Template.reset!
11
+ end
12
+
13
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: braai
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mark Bates
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Fully extensible templating system.
31
+ email:
32
+ - mark@markbates.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - Gemfile.lock
40
+ - LICENSE.txt
41
+ - README.md
42
+ - Rakefile
43
+ - braai.gemspec
44
+ - lib/braai.rb
45
+ - lib/braai/configuration.rb
46
+ - lib/braai/context.rb
47
+ - lib/braai/errors.rb
48
+ - lib/braai/handlers.rb
49
+ - lib/braai/template.rb
50
+ - lib/braai/version.rb
51
+ - spec/braai/handlers_spec.rb
52
+ - spec/braai/template_spec.rb
53
+ - spec/spec_helper.rb
54
+ homepage: ''
55
+ licenses: []
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 1.8.24
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: Fully extensible templating system.
78
+ test_files:
79
+ - spec/braai/handlers_spec.rb
80
+ - spec/braai/template_spec.rb
81
+ - spec/spec_helper.rb