neapolitan 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.rdoc +14 -0
- data/LICENSE +23 -0
- data/README.rdoc +46 -0
- data/bin/neapolitan +3 -0
- data/lib/neapolitan.rb +2 -0
- data/lib/neapolitan/command.rb +84 -0
- data/lib/neapolitan/config.rb +30 -0
- data/lib/neapolitan/document.rb +76 -0
- data/lib/neapolitan/factory.rb +209 -0
- data/lib/neapolitan/meta/data.rb +27 -0
- data/lib/neapolitan/meta/gemfile +13 -0
- data/lib/neapolitan/meta/profile +23 -0
- data/lib/neapolitan/part.rb +36 -0
- data/lib/neapolitan/template.rb +150 -0
- data/meta/data.rb +27 -0
- data/meta/gemfile +13 -0
- data/meta/profile +23 -0
- data/qed/fixtures/example.html +39 -0
- data/qed/fixtures/example.npt +33 -0
- data/qed/fixtures/example.yaml +5 -0
- data/qed/overview.rdoc +81 -0
- metadata +188 -0
data/HISTORY.rdoc
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009 Thomas Sawyer
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
22
|
+
|
23
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
= Neapolitan
|
2
|
+
|
3
|
+
* home: http://rubyworks.github.com/neapolitan
|
4
|
+
* code: http://github.com/rubyworks/neapolitan
|
5
|
+
|
6
|
+
|
7
|
+
== DESCRIPTION
|
8
|
+
|
9
|
+
There are many markup and templating systems in the
|
10
|
+
world. Why be limited to just one? Neapolitan gives
|
11
|
+
you a whole box to pick from.
|
12
|
+
|
13
|
+
|
14
|
+
== FEATURES/ISSUES
|
15
|
+
|
16
|
+
* All the variety of a Whitman's Sampler.
|
17
|
+
* And all the ease of a Hershey's K.I.S.S.
|
18
|
+
* Website uses pretty colors ;)
|
19
|
+
|
20
|
+
|
21
|
+
== SYNOPSIS
|
22
|
+
|
23
|
+
For now please see the Neapolitan website and API documentation.
|
24
|
+
|
25
|
+
|
26
|
+
== HOW TO INSTALL
|
27
|
+
|
28
|
+
You know the routine ;)
|
29
|
+
|
30
|
+
$ sudo gem install neapolitan
|
31
|
+
|
32
|
+
If you're old fashion and want to install to a site
|
33
|
+
location, see Setup.rb (http://protuils.github.com/setup).
|
34
|
+
|
35
|
+
|
36
|
+
== COPYRIGHT/LICENSE
|
37
|
+
|
38
|
+
Neapolitan, Copyright (c) 2010 Thomas Sawyer
|
39
|
+
|
40
|
+
Neapolitan is distributed under the terms of the Apache License v2.0.
|
41
|
+
|
42
|
+
THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
43
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
44
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
45
|
+
PURPOSE.
|
46
|
+
|
data/bin/neapolitan
ADDED
data/lib/neapolitan.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'neapolitan'
|
2
|
+
|
3
|
+
module Neapolitan
|
4
|
+
|
5
|
+
# Command line interface.
|
6
|
+
|
7
|
+
class Command
|
8
|
+
|
9
|
+
def self.main(*argv)
|
10
|
+
new(*argv).call
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(*argv)
|
14
|
+
@output = nil
|
15
|
+
@noharm = false
|
16
|
+
@trace = false
|
17
|
+
@data_file = nil
|
18
|
+
|
19
|
+
parser.parse!(argv)
|
20
|
+
|
21
|
+
@files = argv
|
22
|
+
end
|
23
|
+
|
24
|
+
def parser
|
25
|
+
OptionParser.new do |opt|
|
26
|
+
opt.banner = "neapolitan [file1 file2 ...]"
|
27
|
+
|
28
|
+
opt.on("--output", "-o [PATH]", "save output to specified directory") do |path|
|
29
|
+
@output = path
|
30
|
+
end
|
31
|
+
|
32
|
+
opt.on("--source", "-s [FILE]", "source data file") do |file|
|
33
|
+
@data_file = file
|
34
|
+
end
|
35
|
+
|
36
|
+
opt.on("--trace", "show extra operational information") do
|
37
|
+
$TRACE = true
|
38
|
+
end
|
39
|
+
|
40
|
+
opt.on("--dryrun", "-n", "don't actually write to disk") do
|
41
|
+
$DRYRUN = true
|
42
|
+
end
|
43
|
+
|
44
|
+
opt.on("--debug", "run in debug mode") do
|
45
|
+
$DEBUG = true
|
46
|
+
$VERBOSE = true
|
47
|
+
end
|
48
|
+
|
49
|
+
opt.on_tail("--help", "display this help message") do
|
50
|
+
puts opt
|
51
|
+
exit
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
def call
|
58
|
+
begin
|
59
|
+
@files.each do |file|
|
60
|
+
doc = Document.new(file, data)
|
61
|
+
if @output
|
62
|
+
#doc.save
|
63
|
+
else
|
64
|
+
puts doc
|
65
|
+
end
|
66
|
+
end
|
67
|
+
rescue => e
|
68
|
+
$DEBUG ? raise(e) : puts(e.message)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
def data
|
74
|
+
if @data_file
|
75
|
+
YAML.load(File.new(@data_file))
|
76
|
+
else
|
77
|
+
{} #@source ||= YAML.load(STDIN.read)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Neapolitan
|
4
|
+
|
5
|
+
# Configuration
|
6
|
+
class Config
|
7
|
+
|
8
|
+
#
|
9
|
+
DEFAULTS = {
|
10
|
+
:stencil => 'rhtml',
|
11
|
+
#:format => 'html',
|
12
|
+
:pagelayout => 'page',
|
13
|
+
:postlayout => 'post',
|
14
|
+
:maxchars => 500,
|
15
|
+
}
|
16
|
+
|
17
|
+
attr :defaults
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
if File.exist?('.config/defaults')
|
21
|
+
custom_defaults = YAML.load(File.new('.config/defaults'))
|
22
|
+
else
|
23
|
+
custom_defaults = {}
|
24
|
+
end
|
25
|
+
@defaults = OpenStruct.new(DEFAULTS.merge(custom_defaults))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'neapolitan/template'
|
2
|
+
|
3
|
+
module Neapolitan
|
4
|
+
|
5
|
+
# = Neapolitan Document
|
6
|
+
#
|
7
|
+
# The Document class encapsulates a file which
|
8
|
+
# can be then be rendered via a Neapolitan::Template.
|
9
|
+
class Document
|
10
|
+
|
11
|
+
# File path.
|
12
|
+
attr :file
|
13
|
+
|
14
|
+
#
|
15
|
+
attr :template
|
16
|
+
|
17
|
+
# New Document object.
|
18
|
+
#
|
19
|
+
# file - path to neapolitan formatted file
|
20
|
+
# options - configuration passed on to the Template class
|
21
|
+
#
|
22
|
+
# Returns a new Document object.
|
23
|
+
def initialize(file, options={})
|
24
|
+
case file
|
25
|
+
when File
|
26
|
+
@file = file.name
|
27
|
+
@text = file.read
|
28
|
+
@file.close
|
29
|
+
when String
|
30
|
+
@file = file
|
31
|
+
@text = File.read(file)
|
32
|
+
end
|
33
|
+
|
34
|
+
@template = Template.new(@text, options)
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
def inspect
|
39
|
+
"<#{self.class}: @file='#{file}'>"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Name of file less extname.
|
43
|
+
#def name
|
44
|
+
# @name ||= file.chomp(File.extname(file))
|
45
|
+
#end
|
46
|
+
|
47
|
+
#
|
48
|
+
def render(data={}, &block)
|
49
|
+
@template.render(data, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
# TODO: how to handle extension?
|
53
|
+
def save(*path_and_data, &block)
|
54
|
+
data = Hash===path_and_data.last ? path_and_data.pop : {}
|
55
|
+
path = path_and_data
|
56
|
+
|
57
|
+
rendering = render(data, &block)
|
58
|
+
extension = rendering.header['extension'] || '.html'
|
59
|
+
|
60
|
+
path = Dir.pwd unless path
|
61
|
+
if File.directory?(path)
|
62
|
+
file = File.join(path, file.chomp(File.extname(file)) + extension)
|
63
|
+
else
|
64
|
+
file = path
|
65
|
+
end
|
66
|
+
|
67
|
+
if $DRYRUN
|
68
|
+
$stderr << "[DRYRUN] write #{fname}"
|
69
|
+
else
|
70
|
+
File.open(fname, 'w'){ |f| f << rendering.to_s }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
#require 'tilt'
|
2
|
+
require 'malt'
|
3
|
+
|
4
|
+
module Neapolitan
|
5
|
+
|
6
|
+
# Controls rendering to a variety of back-end templating
|
7
|
+
# and markup systems.
|
8
|
+
#
|
9
|
+
module Factory
|
10
|
+
extend self
|
11
|
+
|
12
|
+
#
|
13
|
+
def render(format, text, source, &yld)
|
14
|
+
#table = {}
|
15
|
+
#scope = Object.new
|
16
|
+
|
17
|
+
case source
|
18
|
+
when Hash
|
19
|
+
db = source
|
20
|
+
when Binding
|
21
|
+
db = source
|
22
|
+
else # object scope
|
23
|
+
db = source
|
24
|
+
end
|
25
|
+
|
26
|
+
case format
|
27
|
+
when /^coderay/
|
28
|
+
coderay(text, format)
|
29
|
+
when /^syntax/
|
30
|
+
syntax(text, format)
|
31
|
+
else
|
32
|
+
doc = Malt.text(text, :format=>format.to_sym)
|
33
|
+
doc.render(db, &yld)
|
34
|
+
#if engine = Tilt[format]
|
35
|
+
# engine.new{text}.render(scope, table, &yld)
|
36
|
+
#else
|
37
|
+
# text
|
38
|
+
#end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
#def redcloth(input)
|
44
|
+
# RedCloth.new(input).to_html
|
45
|
+
#end
|
46
|
+
|
47
|
+
#def bluecloth(input)
|
48
|
+
# BlueCloth.new(input).to_html
|
49
|
+
#end
|
50
|
+
|
51
|
+
#def rdiscount(input)
|
52
|
+
# RDiscount.new(input).to_html
|
53
|
+
#end
|
54
|
+
|
55
|
+
def rdoc(input)
|
56
|
+
markup = RDoc::Markup::ToHtml.new
|
57
|
+
markup.convert(input)
|
58
|
+
end
|
59
|
+
|
60
|
+
#def haml(input)
|
61
|
+
# Haml::Engine.new(input).render
|
62
|
+
#end
|
63
|
+
|
64
|
+
def coderay(input, format)
|
65
|
+
require 'coderay'
|
66
|
+
format = format.split('.')[1] || :ruby #:plaintext
|
67
|
+
tokens = CodeRay.scan(input, format.to_sym) #:ruby
|
68
|
+
tokens.div()
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
def syntax(input, format)
|
73
|
+
require 'syntax/convertors/html'
|
74
|
+
format = format.split('.')[1] || 'ruby' #:plaintext
|
75
|
+
lines = true
|
76
|
+
conv = Syntax::Convertors::HTML.for_syntax(format)
|
77
|
+
conv.convert(input,lines)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Stencil Rendering
|
81
|
+
# -----------------
|
82
|
+
|
83
|
+
#
|
84
|
+
#def render_stencil(stencil, text, attributes)
|
85
|
+
# case stencil
|
86
|
+
# when 'rhtml'
|
87
|
+
# erb(text, attributes)
|
88
|
+
# when 'liquid'
|
89
|
+
# liquid(text, attributes)
|
90
|
+
# else
|
91
|
+
# text
|
92
|
+
# end
|
93
|
+
#end
|
94
|
+
|
95
|
+
#
|
96
|
+
#def erb(input, attributes)
|
97
|
+
# template = ERB.new(input)
|
98
|
+
# context = TemplateContext.new(attributes)
|
99
|
+
# result = template.result(context.__binding__)
|
100
|
+
# result
|
101
|
+
#end
|
102
|
+
|
103
|
+
#def liquid(input, attributes)
|
104
|
+
# template = Liquid::Template.parse(input)
|
105
|
+
# result = template.render(attributes, :filters => [TemplateFilters])
|
106
|
+
# result
|
107
|
+
#end
|
108
|
+
|
109
|
+
=begin
|
110
|
+
# Require Dependencies
|
111
|
+
# --------------------
|
112
|
+
|
113
|
+
# TODO: Load engines only if used.
|
114
|
+
|
115
|
+
begin ; require 'rubygems' ; rescue LoadError ; end
|
116
|
+
begin ; require 'erb' ; rescue LoadError ; end
|
117
|
+
begin ; require 'redcloth' ; rescue LoadError ; end
|
118
|
+
begin ; require 'bluecloth' ; rescue LoadError ; end
|
119
|
+
begin ; require 'rdiscount' ; rescue LoadError ; end
|
120
|
+
|
121
|
+
begin
|
122
|
+
require 'liquid'
|
123
|
+
#Liquid::Template.register_filter(TemplateFilters)
|
124
|
+
rescue LoadError
|
125
|
+
end
|
126
|
+
|
127
|
+
begin
|
128
|
+
require 'haml'
|
129
|
+
#Haml::Template.options[:format] = :html5
|
130
|
+
rescue LoadError
|
131
|
+
end
|
132
|
+
=end
|
133
|
+
|
134
|
+
begin
|
135
|
+
require 'rdoc/markup'
|
136
|
+
require 'rdoc/markup/to_html'
|
137
|
+
rescue LoadError
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
=begin
|
143
|
+
# = Clean Rendering Context
|
144
|
+
#
|
145
|
+
# The Factory Context is is used by ERB.
|
146
|
+
|
147
|
+
class Context
|
148
|
+
#include TemplateFilters
|
149
|
+
|
150
|
+
instance_methods(true).each{ |m| private m unless m =~ /^__/ }
|
151
|
+
|
152
|
+
def initialize(attributes={})
|
153
|
+
@attributes = attributes
|
154
|
+
end
|
155
|
+
|
156
|
+
def __binding__
|
157
|
+
binding
|
158
|
+
end
|
159
|
+
|
160
|
+
def to_h
|
161
|
+
@attributes
|
162
|
+
end
|
163
|
+
|
164
|
+
def method_missing(s, *a)
|
165
|
+
s = s.to_s
|
166
|
+
@attributes.key?(s) ? @attributes[s] : super
|
167
|
+
end
|
168
|
+
end
|
169
|
+
=end
|
170
|
+
|
171
|
+
#
|
172
|
+
#
|
173
|
+
#
|
174
|
+
|
175
|
+
#module TemplateFilters
|
176
|
+
|
177
|
+
# NOTE: HTML truncate did not work well.
|
178
|
+
|
179
|
+
# # HTML comment regular expression
|
180
|
+
# REM_RE = %r{<\!--(.*?)-->}
|
181
|
+
#
|
182
|
+
# # HTML tag regular expression
|
183
|
+
# TAG_RE = %r{</?\w+((\s+\w+(\s*=\s*(?:"(.|\n)*?"|'(.|\n)*?'|[^'">\s]+))?)+\s*|\s*)/?>} #'
|
184
|
+
#
|
185
|
+
# #
|
186
|
+
# def truncate_html(html, limit)
|
187
|
+
# return html unless limit
|
188
|
+
#
|
189
|
+
# mask = html.gsub(REM_RE){ |m| "\0" * m.size }
|
190
|
+
# mask = mask.gsub(TAG_RE){ |m| "\0" * m.size }
|
191
|
+
#
|
192
|
+
# i, x = 0, 0
|
193
|
+
#
|
194
|
+
# while i < mask.size && x < limit
|
195
|
+
# x += 1 if mask[i] != "\0"
|
196
|
+
# i += 1
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
# while x > 0 && mask[x,1] == "\0"
|
200
|
+
# x -= 1
|
201
|
+
# end
|
202
|
+
#
|
203
|
+
# return html[0..x]
|
204
|
+
# end
|
205
|
+
|
206
|
+
#end
|
207
|
+
|
208
|
+
end
|
209
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Object.__send__(:remove_const, :VERSION) if Object.const_defined?(:VERSION) # becuase Ruby 1.8~ gets in the way
|
2
|
+
|
3
|
+
module Neapolitan
|
4
|
+
|
5
|
+
DIRECTORY = File.dirname(__FILE__)
|
6
|
+
|
7
|
+
def self.gemfile
|
8
|
+
@gemfile ||= (
|
9
|
+
require 'yaml'
|
10
|
+
YAML.load(File.new(DIRECTORY + '/gemfile'))
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.profile
|
15
|
+
@profile ||= (
|
16
|
+
require 'yaml'
|
17
|
+
YAML.load(File.new(DIRECTORY + '/profile'))
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.const_missing(name)
|
22
|
+
key = name.to_s.downcase
|
23
|
+
gemfile[key] || profile[key] || super(name)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
name : neapolitan
|
2
|
+
date : 2010-09-14
|
3
|
+
version : 0.2.0
|
4
|
+
|
5
|
+
requires:
|
6
|
+
- malt
|
7
|
+
- rdiscount (optional, development)
|
8
|
+
- redcloth (optional, development)
|
9
|
+
- haml (optional, development)
|
10
|
+
- rdoc 2.5+ (optional, development, document)
|
11
|
+
- syckle (build)
|
12
|
+
- qed (test)
|
13
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
title : Neapolitan
|
2
|
+
summary : Kid in the Candy Store Templating
|
3
|
+
copyright: Copyright (c) 2010 Thomas Sawyer
|
4
|
+
license : Apache 2.0
|
5
|
+
suite : rubyworks
|
6
|
+
contact : rubyworks-mailinglist@googlegroups.com
|
7
|
+
|
8
|
+
description:
|
9
|
+
Neapolitan is a meta-templating engine. Like a candy store
|
10
|
+
it allows you to pick and choose from a variety of rendering
|
11
|
+
formats in the construction of a single document. Selections
|
12
|
+
include eruby, textile, markdown and many others.
|
13
|
+
|
14
|
+
authors:
|
15
|
+
- Thomas Sawyer
|
16
|
+
|
17
|
+
resources:
|
18
|
+
homepage : http://rubyworks.github.com/neapolitan
|
19
|
+
development : http://github.com/rubyworks/neapolitan
|
20
|
+
reference : http://rubyworks.github.com/neapolitan/docs/api
|
21
|
+
wiki : http://wiki.github.com/rubyworks/neapolitan
|
22
|
+
repository : git://github.com/rubyworks/neapolitan.git
|
23
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'neapolitan/factory'
|
2
|
+
|
3
|
+
module Neapolitan
|
4
|
+
|
5
|
+
# A Part is the section of a page. Pages can be segmented into
|
6
|
+
# parts using the '--- FORMAT' notation.
|
7
|
+
class Part
|
8
|
+
|
9
|
+
# Markup format (html, rdoc, markdown, textile)
|
10
|
+
attr :formats
|
11
|
+
|
12
|
+
# Body of text as given in the part.
|
13
|
+
attr :text
|
14
|
+
|
15
|
+
#
|
16
|
+
def initialize(text, *formats)
|
17
|
+
@text = text
|
18
|
+
@formats = formats
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
def render(data, &block)
|
23
|
+
formats.inject(text) do |rendering, format|
|
24
|
+
factory.render(format, rendering, data, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
def factory
|
30
|
+
Factory
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'neapolitan/part'
|
2
|
+
|
3
|
+
module Neapolitan
|
4
|
+
|
5
|
+
#
|
6
|
+
class Template
|
7
|
+
|
8
|
+
# Template text.
|
9
|
+
attr :text
|
10
|
+
|
11
|
+
# Header data, also known as <i>front matter</i>.
|
12
|
+
attr :header
|
13
|
+
|
14
|
+
# Templating format to apply "whole-clothe".
|
15
|
+
attr :stencil
|
16
|
+
|
17
|
+
# Default format(s) for undecorated parts.
|
18
|
+
# If not set defaults to 'html'.
|
19
|
+
attr :default
|
20
|
+
|
21
|
+
## Output extension (defualt is 'html')
|
22
|
+
#attr :extension
|
23
|
+
|
24
|
+
# Provide template +text+, +data+ and yield +block+.
|
25
|
+
def initialize(text, options={})
|
26
|
+
@text = text
|
27
|
+
@stencil = options[:stencil]
|
28
|
+
@default = [options[:default] || 'html'].flatten
|
29
|
+
@parts = []
|
30
|
+
parse
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
def inspect
|
35
|
+
"<#{self.class}: @text='#{text[0,10]}'>"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Unrendered template parts.
|
39
|
+
def parts
|
40
|
+
@parts
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
def render(data={}, &block)
|
45
|
+
Rendering.new(self, data, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
#
|
51
|
+
def parse
|
52
|
+
sect = text.split(/^\-\-\-/)
|
53
|
+
|
54
|
+
if sect.size == 1
|
55
|
+
@header = {}
|
56
|
+
@parts << Part.new(sect[0], *[@stencil, @default].compact.flatten)
|
57
|
+
else
|
58
|
+
sect.shift if sect.first.strip.empty?
|
59
|
+
#void = sect.shift if sect.first.strip.empty?
|
60
|
+
head = sect.shift
|
61
|
+
head = YAML::load(head)
|
62
|
+
parse_header(head)
|
63
|
+
|
64
|
+
sect.each do |body|
|
65
|
+
index = body.index("\n")
|
66
|
+
formats = body[0...index].strip
|
67
|
+
formats = formats.split(/\s+/) if String===formats
|
68
|
+
formats = @default if formats.empty?
|
69
|
+
formats << @stencil if @stencil
|
70
|
+
text = body[index+1..-1]
|
71
|
+
@parts << Part.new(text, *formats)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
def parse_header(head)
|
78
|
+
@header = head
|
79
|
+
@stencil = head.delete('stencil'){ @stencil }
|
80
|
+
@default = head.delete('default'){ @default }
|
81
|
+
#@extension = head.delete('extension'){ @extension }
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
# Template Rendering
|
87
|
+
class Rendering
|
88
|
+
|
89
|
+
#
|
90
|
+
attr :template
|
91
|
+
|
92
|
+
# Source of data, can either be an
|
93
|
+
# Hash, Binding or Object.
|
94
|
+
attr :data
|
95
|
+
|
96
|
+
#
|
97
|
+
attr :block
|
98
|
+
|
99
|
+
#
|
100
|
+
def initialize(template, data, &block)
|
101
|
+
@template = template
|
102
|
+
@data = data
|
103
|
+
@block = block
|
104
|
+
|
105
|
+
if !@block
|
106
|
+
case data
|
107
|
+
when Hash
|
108
|
+
yld = data.delete('yield')
|
109
|
+
@block = Proc.new{ yld } if yld
|
110
|
+
end
|
111
|
+
@block = Proc.new{''} unless @block
|
112
|
+
end
|
113
|
+
|
114
|
+
render
|
115
|
+
end
|
116
|
+
|
117
|
+
def to_s
|
118
|
+
#render unless @output
|
119
|
+
@output
|
120
|
+
end
|
121
|
+
|
122
|
+
# Renderings of each part.
|
123
|
+
def to_a
|
124
|
+
#render unless @output
|
125
|
+
@renders
|
126
|
+
end
|
127
|
+
|
128
|
+
# Summary is the rendering of the first part.
|
129
|
+
def summary
|
130
|
+
#render unless @output
|
131
|
+
@summary
|
132
|
+
end
|
133
|
+
|
134
|
+
#
|
135
|
+
def header
|
136
|
+
@template.header
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
def render
|
142
|
+
@renders = @template.parts.map{ |part| part.render(@data, &@block) }
|
143
|
+
@summary = @renders.first
|
144
|
+
@output = @renders.join("\n")
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
data/meta/data.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Object.__send__(:remove_const, :VERSION) if Object.const_defined?(:VERSION) # becuase Ruby 1.8~ gets in the way
|
2
|
+
|
3
|
+
module Neapolitan
|
4
|
+
|
5
|
+
DIRECTORY = File.dirname(__FILE__)
|
6
|
+
|
7
|
+
def self.gemfile
|
8
|
+
@gemfile ||= (
|
9
|
+
require 'yaml'
|
10
|
+
YAML.load(File.new(DIRECTORY + '/gemfile'))
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.profile
|
15
|
+
@profile ||= (
|
16
|
+
require 'yaml'
|
17
|
+
YAML.load(File.new(DIRECTORY + '/profile'))
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.const_missing(name)
|
22
|
+
key = name.to_s.downcase
|
23
|
+
gemfile[key] || profile[key] || super(name)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
data/meta/gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
name : neapolitan
|
2
|
+
date : 2010-09-14
|
3
|
+
version : 0.2.0
|
4
|
+
|
5
|
+
requires:
|
6
|
+
- malt
|
7
|
+
- rdiscount (optional, development)
|
8
|
+
- redcloth (optional, development)
|
9
|
+
- haml (optional, development)
|
10
|
+
- rdoc 2.5+ (optional, development, document)
|
11
|
+
- syckle (build)
|
12
|
+
- qed (test)
|
13
|
+
|
data/meta/profile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
title : Neapolitan
|
2
|
+
summary : Kid in the Candy Store Templating
|
3
|
+
copyright: Copyright (c) 2010 Thomas Sawyer
|
4
|
+
license : Apache 2.0
|
5
|
+
suite : rubyworks
|
6
|
+
contact : rubyworks-mailinglist@googlegroups.com
|
7
|
+
|
8
|
+
description:
|
9
|
+
Neapolitan is a meta-templating engine. Like a candy store
|
10
|
+
it allows you to pick and choose from a variety of rendering
|
11
|
+
formats in the construction of a single document. Selections
|
12
|
+
include eruby, textile, markdown and many others.
|
13
|
+
|
14
|
+
authors:
|
15
|
+
- Thomas Sawyer
|
16
|
+
|
17
|
+
resources:
|
18
|
+
homepage : http://rubyworks.github.com/neapolitan
|
19
|
+
development : http://github.com/rubyworks/neapolitan
|
20
|
+
reference : http://rubyworks.github.com/neapolitan/docs/api
|
21
|
+
wiki : http://wiki.github.com/rubyworks/neapolitan
|
22
|
+
repository : git://github.com/rubyworks/neapolitan.git
|
23
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<h1>Yummy Choclate </h1>
|
2
|
+
<p>
|
3
|
+
Hi Ginger,
|
4
|
+
</p>
|
5
|
+
<p>
|
6
|
+
I know you want some of that yummy stuff.
|
7
|
+
</p>
|
8
|
+
|
9
|
+
<div class="CodeRay">
|
10
|
+
<div class="code"><pre>
|
11
|
+
<span style="background-color:#fff0f0;color:#D20"><span style="color:#710">%{</span><span style="">c h o c o l a t e s</span><span style="color:#710">}</span></span>.each <span style="color:#080;font-weight:bold">do</span> |letter|
|
12
|
+
puts <span style="background-color:#fff0f0;color:#D20"><span style="color:#710">"</span><span style="">Give me a </span><span style="background:#ddd;color:black"><span style="background:#ddd;font-weight:bold;color:#666">#{</span>letter<span style="background:#ddd;font-weight:bold;color:#666">}</span></span><span style="">!</span><span style="color:#710">"</span></span>
|
13
|
+
<span style="color:#080;font-weight:bold">end</span>
|
14
|
+
|
15
|
+
puts <span style="background-color:#fff0f0;color:#D20"><span style="color:#710">"</span><span style="">What's that spell?</span><span style="color:#710">"</span></span>
|
16
|
+
|
17
|
+
</pre></div>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
|
21
|
+
<quote>
|
22
|
+
What can I say?
|
23
|
+
|
24
|
+
</quote>
|
25
|
+
|
26
|
+
|
27
|
+
<table>
|
28
|
+
<tr>
|
29
|
+
<td> </td>
|
30
|
+
<td> 2009 </td>
|
31
|
+
<td> 2010 </td>
|
32
|
+
</tr>
|
33
|
+
<tr>
|
34
|
+
<td> Has Choclates? </td>
|
35
|
+
<td> No </td>
|
36
|
+
<td> Yes! </td>
|
37
|
+
</tr>
|
38
|
+
</table>
|
39
|
+
<p>As you can see. It's all <em>fun</em> and <em>games</em> here.</p>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
extension: html
|
2
|
+
|
3
|
+
--- rdoc erb
|
4
|
+
|
5
|
+
= Yummy Choclate
|
6
|
+
|
7
|
+
Hi <%= name %>,
|
8
|
+
|
9
|
+
I know you want some of that yummy stuff.
|
10
|
+
|
11
|
+
--- coderay.ruby
|
12
|
+
|
13
|
+
%{c h o c o l a t e s}.each do |letter|
|
14
|
+
puts "Give me a #{letter}!"
|
15
|
+
end
|
16
|
+
|
17
|
+
puts "What's that spell?"
|
18
|
+
|
19
|
+
--- html liquid
|
20
|
+
|
21
|
+
<quote>
|
22
|
+
{{ yield }}
|
23
|
+
</quote>
|
24
|
+
|
25
|
+
--- textile
|
26
|
+
|
27
|
+
| | 2009 | 2010 |
|
28
|
+
| Has Choclates? | No | Yes! |
|
29
|
+
|
30
|
+
--- markdown
|
31
|
+
|
32
|
+
As you can see. It's all _fun_ and _games_ here.
|
33
|
+
|
data/qed/overview.rdoc
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
= Example Neapolitan Document
|
2
|
+
|
3
|
+
Here is an example neapolitan file, 'example.choc':
|
4
|
+
|
5
|
+
extension: html
|
6
|
+
|
7
|
+
--- rdoc erb
|
8
|
+
|
9
|
+
= Yummy Vanilla
|
10
|
+
|
11
|
+
Hi <%= name %>,
|
12
|
+
|
13
|
+
I know you want some of that yummy stuff.
|
14
|
+
|
15
|
+
--- coderay.ruby
|
16
|
+
|
17
|
+
%{S t r a w b e r r y}.each do |letter|
|
18
|
+
puts "Give me a #{letter}!"
|
19
|
+
end
|
20
|
+
|
21
|
+
puts "What's that spell?"
|
22
|
+
|
23
|
+
--- html liquid
|
24
|
+
|
25
|
+
<quote>
|
26
|
+
{{ yield }}
|
27
|
+
</quote>
|
28
|
+
|
29
|
+
--- textile
|
30
|
+
|
31
|
+
| | 2009 | 2010 |
|
32
|
+
| Has Choclate? | No | Yes! |
|
33
|
+
|
34
|
+
--- markdown
|
35
|
+
|
36
|
+
As you can see. It's all _fun_ and _games_ here.
|
37
|
+
|
38
|
+
= Loading the Library
|
39
|
+
|
40
|
+
Require the library.
|
41
|
+
|
42
|
+
require 'neapolitan'
|
43
|
+
|
44
|
+
= Reading a Neapolitan File
|
45
|
+
|
46
|
+
Load our example template[fixtures/example.npt].
|
47
|
+
|
48
|
+
file = "qed/fixtures/example.npt"
|
49
|
+
|
50
|
+
document = Neapolitan::Document.new(file)
|
51
|
+
|
52
|
+
= Rendering Data Sources
|
53
|
+
|
54
|
+
Neapolitan uses Malt on the backend. Malt supports a three separate ways to pass
|
55
|
+
data into a template.
|
56
|
+
|
57
|
+
The most obvious data source is a Hash.
|
58
|
+
|
59
|
+
data = {:name=>"Tom"}
|
60
|
+
|
61
|
+
text = document.render(data).to_s
|
62
|
+
|
63
|
+
text.assert =~ /Hi Tom/
|
64
|
+
|
65
|
+
Templates can also be rendered given a Binding.
|
66
|
+
|
67
|
+
name = "Huck"
|
68
|
+
|
69
|
+
text = document.render(binding).to_s
|
70
|
+
|
71
|
+
text.assert =~ /Hi Huck/
|
72
|
+
|
73
|
+
And lastly, they can be renderedwith the scope of any other type of Object,
|
74
|
+
including an instance of a Struct.
|
75
|
+
|
76
|
+
scope = Struct.new(:name).new("Becky")
|
77
|
+
|
78
|
+
text = document.render(scope).to_s
|
79
|
+
|
80
|
+
text.assert =~ /Hi Becky/
|
81
|
+
|
metadata
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: neapolitan
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Thomas Sawyer
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-09-14 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: malt
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rdiscount
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: redcloth
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: haml
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :development
|
76
|
+
version_requirements: *id004
|
77
|
+
- !ruby/object:Gem::Dependency
|
78
|
+
name: rdoc
|
79
|
+
prerelease: false
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 9
|
86
|
+
segments:
|
87
|
+
- 2
|
88
|
+
- 5
|
89
|
+
version: "2.5"
|
90
|
+
type: :development
|
91
|
+
version_requirements: *id005
|
92
|
+
- !ruby/object:Gem::Dependency
|
93
|
+
name: syckle
|
94
|
+
prerelease: false
|
95
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
hash: 3
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
version: "0"
|
104
|
+
type: :development
|
105
|
+
version_requirements: *id006
|
106
|
+
- !ruby/object:Gem::Dependency
|
107
|
+
name: qed
|
108
|
+
prerelease: false
|
109
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
hash: 3
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
version: "0"
|
118
|
+
type: :development
|
119
|
+
version_requirements: *id007
|
120
|
+
description: Neapolitan is a meta-templating engine. Like a candy store it allows you to pick and choose from a variety of rendering formats in the construction of a single document. Selections include eruby, textile, markdown and many others.
|
121
|
+
email: rubyworks-mailinglist@googlegroups.com
|
122
|
+
executables:
|
123
|
+
- neapolitan
|
124
|
+
extensions: []
|
125
|
+
|
126
|
+
extra_rdoc_files:
|
127
|
+
- README.rdoc
|
128
|
+
files:
|
129
|
+
- bin/neapolitan
|
130
|
+
- lib/neapolitan/command.rb
|
131
|
+
- lib/neapolitan/config.rb
|
132
|
+
- lib/neapolitan/document.rb
|
133
|
+
- lib/neapolitan/factory.rb
|
134
|
+
- lib/neapolitan/meta/data.rb
|
135
|
+
- lib/neapolitan/meta/gemfile
|
136
|
+
- lib/neapolitan/meta/profile
|
137
|
+
- lib/neapolitan/part.rb
|
138
|
+
- lib/neapolitan/template.rb
|
139
|
+
- lib/neapolitan.rb
|
140
|
+
- meta/data.rb
|
141
|
+
- meta/gemfile
|
142
|
+
- meta/profile
|
143
|
+
- qed/fixtures/example.html
|
144
|
+
- qed/fixtures/example.npt
|
145
|
+
- qed/fixtures/example.yaml
|
146
|
+
- qed/overview.rdoc
|
147
|
+
- HISTORY.rdoc
|
148
|
+
- LICENSE
|
149
|
+
- README.rdoc
|
150
|
+
has_rdoc: true
|
151
|
+
homepage: http://rubyworks.github.com/neapolitan
|
152
|
+
licenses:
|
153
|
+
- Apache 2.0
|
154
|
+
post_install_message:
|
155
|
+
rdoc_options:
|
156
|
+
- --title
|
157
|
+
- Neapolitan API
|
158
|
+
- --main
|
159
|
+
- README.rdoc
|
160
|
+
require_paths:
|
161
|
+
- lib
|
162
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
163
|
+
none: false
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
hash: 3
|
168
|
+
segments:
|
169
|
+
- 0
|
170
|
+
version: "0"
|
171
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
|
+
none: false
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
hash: 3
|
177
|
+
segments:
|
178
|
+
- 0
|
179
|
+
version: "0"
|
180
|
+
requirements: []
|
181
|
+
|
182
|
+
rubyforge_project: neapolitan
|
183
|
+
rubygems_version: 1.3.7
|
184
|
+
signing_key:
|
185
|
+
specification_version: 3
|
186
|
+
summary: Kid in the Candy Store Templating
|
187
|
+
test_files: []
|
188
|
+
|