masover-re_template 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/README +64 -0
- data/lib/re_template/html.rb +49 -0
- data/lib/re_template/text.rb +35 -0
- data/lib/re_template.rb +24 -0
- metadata +65 -0
data/README
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
A very simple template engine based on Regular Expressions
|
2
|
+
|
3
|
+
|
4
|
+
Features
|
5
|
+
========
|
6
|
+
|
7
|
+
* Regular expressions or plain text
|
8
|
+
* Can be used for HTML->HTML (read on)
|
9
|
+
* Tested on Ruby 1.8.7 and 1.9.1
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
Usage
|
14
|
+
=====
|
15
|
+
|
16
|
+
template = ReTemplate::Text.new
|
17
|
+
template.expressions = {/\{foo\}/ => :foo, /\{bar\}/ => :bar}
|
18
|
+
template.parse! 'A {foo} is not a {bar}.'
|
19
|
+
template.render :foo => 'plant', :bar => 'rhinocerous', :other_expression => 'ignored'
|
20
|
+
=> 'A plant is not a rhinocerous.'
|
21
|
+
|
22
|
+
Expressions must be set before parsing.
|
23
|
+
Multiple calls to parse! can be done with the same expressions (this may change).
|
24
|
+
Multiple calls to 'render' will work by design.
|
25
|
+
It also works with HTML:
|
26
|
+
|
27
|
+
template = ReTemplate::Html.new
|
28
|
+
template.add_text_expressions '<foo>' => :foo, '|lang|' => :lang
|
29
|
+
template.parse! '<p><foo> is not a valid |lang| tag.</p>'
|
30
|
+
template.render :foo => '<bar>', :lang => 'HTML'
|
31
|
+
=> '<p><bar> is not a valid HTML tag.</p>'
|
32
|
+
|
33
|
+
Actually, I lied, as this will currently attach a doctype, and wrap things in html and body tags, if any of these things are missing. I blame Nokogiri.
|
34
|
+
|
35
|
+
Read the specs for more.
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
Motivation/Examples
|
40
|
+
===================
|
41
|
+
|
42
|
+
Mail merge. A user can prepare an email like this, in their mail client:
|
43
|
+
|
44
|
+
Dear {customer_name},
|
45
|
+
Lorem ipsum dolor sit amet...
|
46
|
+
|
47
|
+
The curly brackets are merely a convention, because {user} is unlikely to be intended in the body of a message. The important point is that this can also be applied to an HTML message, even if the pattern or replacement text is not valid HTML. For example:
|
48
|
+
|
49
|
+
Dear <customer_name>,
|
50
|
+
|
51
|
+
A simple text replacement would only see <user>. While we're at it, the replacement text is automatically escaped.
|
52
|
+
|
53
|
+
I also looked at Liquid. It is very cool, but it was overkill for this project, and it didn't look like it would behave well with WYSIWYG-generated HTML.
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
CAVEATS
|
58
|
+
=======
|
59
|
+
|
60
|
+
This is brand spanking this-afternoon new. The API is pretty much guaranteed to change. If you're using this for anything important, either fork it or lock to a specific version.
|
61
|
+
|
62
|
+
The expressions hash is unordered. If you have a chunk of text that could match two different regular expressions, one of them is going to be applied first, and it's undefined which one. If this matters to you, you're probably using the wrong tool -- personally, I won't be using the regexes directly at all, they just seem to be faster (for some bizarre reason) than string#split.
|
63
|
+
|
64
|
+
Someone MUST have done a better job of this somewhere. If you find it, let me know!
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
class ReTemplate::Html < ReTemplate
|
4
|
+
attr_accessor :doc
|
5
|
+
def parse! given_doc
|
6
|
+
if given_doc.kind_of? String
|
7
|
+
self.doc = Nokogiri::HTML.parse(given_doc)
|
8
|
+
else
|
9
|
+
self.doc = given_doc.dup
|
10
|
+
end
|
11
|
+
|
12
|
+
self.nodes = []
|
13
|
+
|
14
|
+
parse_children! doc
|
15
|
+
end
|
16
|
+
|
17
|
+
def render values
|
18
|
+
nodes.each do |node|
|
19
|
+
node.render! values
|
20
|
+
end
|
21
|
+
doc.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
class SubTemplate < Text
|
25
|
+
attr_accessor :node
|
26
|
+
def initialize node, expressions
|
27
|
+
self.node = node
|
28
|
+
self.expressions = expressions
|
29
|
+
self.parse! node.text
|
30
|
+
end
|
31
|
+
|
32
|
+
def render! values
|
33
|
+
new_node = Nokogiri::XML::Text.new(render(values), node.document)
|
34
|
+
node.replace(new_node)
|
35
|
+
self.node = new_node
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
def parse_children! node
|
41
|
+
if node.kind_of? Nokogiri::XML::Text
|
42
|
+
nodes << SubTemplate.new(node, expressions)
|
43
|
+
else
|
44
|
+
node.children.each do |n|
|
45
|
+
parse_children! n
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class ReTemplate::Text < ReTemplate
|
2
|
+
def parse! string
|
3
|
+
self.nodes = [string]
|
4
|
+
expressions.each_key do |expression|
|
5
|
+
self.nodes = self.nodes.map do |node|
|
6
|
+
if node.kind_of? String
|
7
|
+
result = []
|
8
|
+
rest = node
|
9
|
+
while match = expression.match(rest)
|
10
|
+
result << match.pre_match
|
11
|
+
result << expression
|
12
|
+
rest = match.post_match
|
13
|
+
end
|
14
|
+
result << rest
|
15
|
+
result.reject{|x| x == ''}
|
16
|
+
else
|
17
|
+
# It's not a string, so leave it alone
|
18
|
+
node
|
19
|
+
end
|
20
|
+
end.flatten
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def render values
|
25
|
+
result = ''
|
26
|
+
nodes.each do |node|
|
27
|
+
if node.kind_of? String
|
28
|
+
result << node
|
29
|
+
else
|
30
|
+
result << values[expressions[node]]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
result
|
34
|
+
end
|
35
|
+
end
|
data/lib/re_template.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'autoloader'
|
3
|
+
require 'pathname'
|
4
|
+
AutoLoader << Pathname(__FILE__).dirname
|
5
|
+
|
6
|
+
class ReTemplate
|
7
|
+
include AutoLoader
|
8
|
+
|
9
|
+
attr_accessor :nodes
|
10
|
+
attr_writer :expressions
|
11
|
+
def expressions
|
12
|
+
@expressions ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_text_expressions *args
|
16
|
+
hash = args.last.kind_of?(Hash) ? args.pop : {}
|
17
|
+
args.each do |field|
|
18
|
+
hash[field] = field
|
19
|
+
end
|
20
|
+
hash.each_pair do |key, value|
|
21
|
+
self.expressions[/#{Regexp.escape key}/] = value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: masover-re_template
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Masover
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-10 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: masover-autoloader
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.1
|
24
|
+
version:
|
25
|
+
description:
|
26
|
+
email: dave@3mix.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- README
|
35
|
+
- lib/re_template.rb
|
36
|
+
- lib/re_template/text.rb
|
37
|
+
- lib/re_template/html.rb
|
38
|
+
has_rdoc: false
|
39
|
+
homepage:
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.2.0
|
61
|
+
signing_key:
|
62
|
+
specification_version: 2
|
63
|
+
summary: Simple, Regular Expression powered template engine. Intelligently handles HTML input.
|
64
|
+
test_files: []
|
65
|
+
|