neapolitan 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/neapolitan.rb CHANGED
@@ -1,424 +1,75 @@
1
- require 'neapolitan/meta/data'
2
- #require 'tilt'
3
- require 'malt'
4
-
5
1
  module Neapolitan
6
2
 
3
+ if RUBY_VERSION > '1.9'
4
+ require_relative 'neapolitan/version'
5
+ require_relative 'neapolitan/core_ext'
6
+ require_relative 'neapolitan/template'
7
+ require_relative 'neapolitan/part'
8
+ require_relative 'neapolitan/rendering'
9
+ require_relative 'neapolitan/factory'
10
+ require_relative 'neapolitan/cli'
11
+ else
12
+ require 'neapolitan/version'
13
+ require 'neapolitan/core_ext'
14
+ require 'neapolitan/template'
15
+ require 'neapolitan/part'
16
+ require 'neapolitan/factory'
17
+ require 'neapolitan/rendering'
18
+ require 'neapolitan/cli'
19
+ end
20
+
21
+ # Set default rendering system for all templates.
22
+ # This can either be `:tilt` or `:malt`, the default.
23
+ def self.system(libname=nil)
24
+ @system = libname if libname
25
+ @system
26
+ end
27
+
28
+ # Limit the section formats for all templates to the
29
+ # sepecified selection via a selection procedure.
30
+ def self.select(&select)
31
+ @select = select if select
32
+ @select
33
+ end
34
+
35
+ # Limit the section formats for all templates via
36
+ # a rejection procedure.
37
+ def self.reject(&reject)
38
+ @reject = reject if reject
39
+ @reject
40
+ end
41
+
42
+ # Load template from given source.
43
+ #
44
+ # @param [File,IO,String] source
45
+ # The document to render.
46
+ #
47
+ # @param [Hash] options
48
+ # Rendering options.
7
49
  #
8
50
  def self.load(source, options={})
9
51
  Template.new(source, options)
10
52
  end
11
53
 
54
+ # Specifically create a new template from a text string.
55
+ #
56
+ # @param [#to_s] source
57
+ # The document to render.
58
+ #
59
+ # @param [Hash] options
60
+ # Rendering options.
12
61
  #
13
62
  def self.text(source, options={})
14
63
  Template.new(source.to_s, options)
15
64
  end
16
65
 
66
+ # Specifically create a new template from a file, given the files name.
67
+ #
68
+ # @example
69
+ # Neapolitan::Template.file('example.np')
17
70
  #
18
71
  def self.file(fname, options={})
19
72
  Template.new(File.new(fname), options)
20
73
  end
21
74
 
22
- #
23
- class Template
24
-
25
- # Template text.
26
- attr :text
27
-
28
- # File name of template, if given.
29
- attr :file
30
-
31
- # Templating format to apply "whole-clothe".
32
- attr :stencil
33
-
34
- # Default format(s) for undecorated parts.
35
- # If not otherwise set the default is 'html'.
36
- attr :default
37
-
38
- # Common format(s) to be applied to all parts.
39
- # These are applied at the end.
40
- attr :common
41
-
42
- # Rendering formats to disallow.
43
- #attr :reject
44
-
45
- # Header data, also known as <i>front matter</i>.
46
- attr :header
47
-
48
- #
49
- def initialize(source, options={})
50
- case source
51
- when ::File
52
- @file = source.path #name
53
- @text = source.read
54
- source.close
55
- when ::IO
56
- @text = source.read
57
- @file = options[:file]
58
- source.close
59
- when ::String
60
- @text = source
61
- @file = options[:file]
62
- when Hash
63
- options = source
64
- source = nil
65
- @file = options[:file]
66
- @text = File.read(@file)
67
- end
68
-
69
- @stencil = options[:stencil]
70
- @default = options[:default] || 'html'
71
- @common = options[:common]
72
- #@reject = options[:reject]
73
-
74
- parse
75
- end
76
-
77
- #
78
- def inspect
79
- if file
80
- "<#{self.class}: @file='#{file}'>"
81
- else
82
- "<#{self.class}: @text='#{text[0,10]}'>"
83
- end
84
- end
85
-
86
- # Rejection formats.
87
- #--
88
- # TODO: filter common and default
89
- #++
90
- def reject(&block)
91
- parts.each do |part|
92
- part.formats.reject!(&block)
93
- end
94
- end
95
-
96
- # Select formats.
97
- #--
98
- # TODO: filter common and default
99
- #++
100
- def select(&block)
101
- parts.each do |part|
102
- part.formats.select!(&block)
103
- end
104
- end
105
-
106
- # Unrendered template parts.
107
- def parts
108
- @parts
109
- end
110
-
111
- #
112
- def render(data={}, &block)
113
- if !block
114
- case data
115
- when Hash
116
- yld = data.delete('yield')
117
- block = Proc.new{ yld } if yld
118
- end
119
- block = Proc.new{''} unless block
120
- end
121
-
122
- renders = parts.map{ |part| render_part(part, data, &block) }
123
-
124
- Rendering.new(renders, header)
125
- end
126
-
127
- # :call-seq:
128
- # save(data={}, &block)
129
- # save(file, data={}, &block)
130
- #
131
- def save(*args, &block)
132
- data = Hash===args.last ? args.pop : {}
133
- path = args.first
134
-
135
- rendering = render(data, &block)
136
-
137
- path = path || rendering.header['output']
138
- path = path || path.chomp(File.extname(file))
139
-
140
- path = Dir.pwd unless path
141
- if File.directory?(path)
142
- file = File.join(path, file.chomp(File.extname(file)) + extension)
143
- else
144
- file = path
145
- end
146
-
147
- if $DRYRUN
148
- $stderr << "[DRYRUN] write #{fname}"
149
- else
150
- File.open(file, 'w'){ |f| f << rendering.to_s }
151
- end
152
- end
153
-
154
- private
155
-
156
- #--
157
- # TODO: Should a stencil be applied once to the entire document?
158
- #++
159
- def parse
160
- @parts = []
161
-
162
- sect = text.split(/^\-\-\-/)
163
-
164
- if sect.size == 1
165
- @header = {}
166
- @parts << Part.new(sect[0]) #, *[@stencil, @default].compact.flatten)
167
- else
168
- sect.shift if sect.first.strip.empty?
169
-
170
- head = sect.shift
171
- head = YAML::load(head)
172
- parse_header(head)
173
-
174
- sect.each do |body|
175
- index = body.index("\n")
176
- formats = body[0...index].strip
177
- formats = formats.split(/\s+/) if String===formats
178
- #formats = @default if formats.empty?
179
- #formats.unshift(@stencil) if @stencil
180
- text = body[index+1..-1]
181
- @parts << Part.new(text, *formats)
182
- end
183
- end
184
- end
185
-
186
- #
187
- def parse_header(head)
188
- @header = head
189
- @default = head.delete('default'){ @default }
190
- @common = head.delete('common'){ @common }
191
- end
192
-
193
- #
194
- def render_part(part, data, &block)
195
- formats = part.formats
196
- formats = default if formats.empty?
197
- formats = [formats, common].flatten.compact
198
-
199
- #case reject
200
- #when Array
201
- # formats = formats - reject.map{|r|r.to_s}
202
- #when Proc
203
- # formats = formats.reject(&reject)
204
- #end
205
-
206
- formats = [stencil, *formats].compact
207
-
208
- formats.inject(part.text) do |text, format|
209
- factory.render(text, format, data, &block)
210
- end
211
- end
212
-
213
- #
214
- def factory
215
- @factory ||= Factory.new
216
- end
217
-
218
- end
219
-
220
- # A part is a section of a template. Templates can be segmented into
221
- # parts using the '--- FORMAT' notation.
222
- class Part
223
- # Rendering formats (html, rdoc, markdown, textile, etc.)
224
- attr :formats
225
-
226
- # Body of text as given in the part.
227
- attr :text
228
-
229
- #
230
- def initialize(text, *formats)
231
- @text = text
232
- @formats = formats
233
- end
234
- end
235
-
236
- # Template Rendering
237
- class Rendering
238
- #
239
- def initialize(renders, header)
240
- @renders = renders
241
- @summary = renders.first
242
- @output = renders.join("\n")
243
- @header = header
244
- end
245
-
246
- #
247
- def to_s
248
- @output
249
- end
250
-
251
- # Renderings of each part.
252
- def to_a
253
- @renders
254
- end
255
-
256
- # Summary is the rendering of the first part.
257
- def summary
258
- @summary
259
- end
260
-
261
- #
262
- def header
263
- @header
264
- end
265
- end
266
-
267
- # Controls rendering to a variety of back-end templating
268
- # and markup systems via Malt.
269
- class Factory
270
- #
271
- attr :types
272
-
273
- #
274
- def initialize(options={})
275
- @types = options[:types]
276
- end
277
-
278
- #
279
- def render(text, format, data, &yld)
280
- case format
281
- when /^coderay/
282
- coderay(text, format)
283
- when /^syntax/
284
- syntax(text, format)
285
- else
286
- render_via_malt(text, format, data, &yld)
287
- end
288
- end
289
-
290
- #
291
- def render_via_malt(text, format, data, &yld)
292
- doc = malt.text(text, :type=>format.to_sym)
293
- doc.render(data, &yld)
294
- end
295
-
296
- #
297
- def render_via_tilt(text, format, data, &yld)
298
- if engine = Tilt[format]
299
- case data
300
- when Hash
301
- scope = Object.new
302
- table = data
303
- when Binding
304
- scope = data.eval('self')
305
- table = {}
306
- else # object scope
307
- scope = data
308
- table = {}
309
- end
310
- engine.new{text}.render(scope, table, &yld)
311
- else
312
- text
313
- end
314
- end
315
-
316
- #
317
- def malt
318
- @malt ||= (
319
- if types && !types.empty?
320
- Malt::Machine.new(:types=>types)
321
- else
322
- Malt::Machine.new
323
- end
324
- )
325
- end
326
-
327
- def coderay(input, format)
328
- require 'coderay'
329
- format = format.split('.')[1] || :ruby #:plaintext
330
- tokens = CodeRay.scan(input, format.to_sym) #:ruby
331
- tokens.div()
332
- end
333
-
334
- #
335
- def syntax(input, format)
336
- require 'syntax/convertors/html'
337
- format = format.split('.')[1] || 'ruby' #:plaintext
338
- lines = true
339
- conv = Syntax::Convertors::HTML.for_syntax(format)
340
- conv.convert(input,lines)
341
- end
342
-
343
- #
344
- #def render_stencil(stencil, text, attributes)
345
- # case stencil
346
- # when 'rhtml'
347
- # erb(text, attributes)
348
- # when 'liquid'
349
- # liquid(text, attributes)
350
- # else
351
- # text
352
- # end
353
- #end
354
-
355
- public
356
-
357
- #
358
- def self.render(text, format, data, &yld)
359
- new.render(text, format, data, &yld)
360
- end
361
-
362
- end
363
-
364
- # Command line interface.
365
- def self.cli(*argv)
366
- options = {}
367
-
368
- option_parser(options).parse!(argv)
369
-
370
- if src = options[:source]
371
- data = YAML.load(File.new(src))
372
- else
373
- data = {} #@source ||= YAML.load(STDIN.read)
374
- end
375
-
376
- files = argv
377
-
378
- begin
379
- files.each do |file|
380
- template = Template.new(File.new(file))
381
- if options[:output]
382
- #template.save(data)
383
- else
384
- puts template.render(data)
385
- end
386
- end
387
- rescue => e
388
- $DEBUG ? raise(e) : puts(e.message)
389
- end
390
- end
391
-
392
- #--
393
- # TODO: Save to output.
394
- #++
395
- def self.option_parser(options)
396
- require 'optparse'
397
-
398
- OptionParser.new do |opt|
399
- opt.banner = "neapolitan [file1 file2 ...]"
400
- #opt.on("--output", "-o [PATH]", "save output to specified directory") do |path|
401
- # options[:output] = path
402
- #end
403
- opt.on("--source", "-s [FILE]", "data souce (YAML file)") do |file|
404
- options[:source] = file
405
- end
406
- opt.on("--trace", "show extra operational information") do
407
- $TRACE = true
408
- end
409
- opt.on("--dryrun", "-n", "don't actually write to disk") do
410
- $DRYRUN = true
411
- end
412
- opt.on("--debug", "run in debug mode") do
413
- $DEBUG = true
414
- $VERBOSE = true
415
- end
416
- opt.on_tail("--help", "display this help message") do
417
- puts opt
418
- exit
419
- end
420
- end
421
-
422
- end
423
-
424
75
  end
@@ -0,0 +1,72 @@
1
+ ---
2
+ source:
3
+ - var
4
+ authors:
5
+ - name: trans
6
+ email: transfire@gmail.com
7
+ copyrights: []
8
+ replacements: []
9
+ alternatives: []
10
+ requirements:
11
+ - name: malt
12
+ version: 0.4.0+
13
+ - name: detroit
14
+ groups:
15
+ - build
16
+ development: true
17
+ - name: yard
18
+ groups:
19
+ - document
20
+ development: true
21
+ - name: qed
22
+ groups:
23
+ - test
24
+ development: true
25
+ - name: coderay
26
+ groups:
27
+ - optional
28
+ - test
29
+ development: true
30
+ - name: RedCloth
31
+ groups:
32
+ - optional
33
+ - test
34
+ development: true
35
+ - name: rdoc
36
+ groups:
37
+ - optional
38
+ - test
39
+ development: true
40
+ - name: liquid
41
+ groups:
42
+ - optional
43
+ - test
44
+ development: true
45
+ dependencies: []
46
+ conflicts: []
47
+ repositories:
48
+ - uri: git://github.com/rubyworks/neapolitan.git
49
+ scm: git
50
+ name: upstream
51
+ resources:
52
+ home: http://rubyworks.github.com/neapolitan
53
+ code: http://github.com/rubyworks/neapolitan
54
+ docs: http://rubydoc.info/gems/neapolitan/frames
55
+ wiki: http://wiki.github.com/rubyworks/neapolitan
56
+ extra: {}
57
+ load_path:
58
+ - lib
59
+ revision: 0
60
+ created: '2009-08-25'
61
+ summary: Kid in the Candy Store Templating
62
+ title: Neapolitan
63
+ version: 0.4.0
64
+ name: neapolitan
65
+ description: ! 'Neapolitan is a meta-templating engine. Like a candy store it allows
66
+ you to pick
67
+
68
+ and choose from a variety of rendering formats in the construction of a single
69
+
70
+ document. Selections include eruby, textile, markdown and many others.'
71
+ organization: rubyworks
72
+ date: '2011-11-30'