braai 1.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 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