neapolitan 0.3.0 → 0.4.0

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/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'