razor 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/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2011 by Ferreira, Christopher
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the Software), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README ADDED
File without changes
@@ -0,0 +1,7 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ $:.unshift './lib'
4
+
5
+ require 'razor/runner'
6
+
7
+ Razor::Runner.new
@@ -0,0 +1,58 @@
1
+ require 'version'
2
+ require 'rubygems'
3
+ require 'fileutils'
4
+
5
+ require 'razor/generable'
6
+ require 'highline'
7
+
8
+ module Razor
9
+
10
+ class << self
11
+ attr :get
12
+ end
13
+
14
+ def self.create(name)
15
+ Dir.mkdir name
16
+ end
17
+
18
+ def self.generate(src, dest)
19
+ site = Site.new(src, dest)
20
+ FileUtils.rm_r(dest) rescue nil
21
+ site.generate
22
+ end
23
+
24
+ def self.server(port, src)
25
+ require 'rack'
26
+ port = (port and port.to_i or 9000)
27
+ on_request = lambda do |env|
28
+ page = Razor.http_request src, env['PATH_INFO']
29
+ p page.dest_name rescue nil
30
+ if page
31
+ [
32
+ 200,
33
+ { 'Content-Type' =>
34
+ Rack::Mime.mime_type(page.dest_ext) },
35
+ [ page.contents ]
36
+ ]
37
+ else
38
+ [
39
+ 404,
40
+ { 'Content-Type' => 'text/html' },
41
+ [ 'Page Not Found' ]
42
+ ]
43
+ end
44
+ end
45
+ Rack::Handler::WEBrick.run(on_request, :Port => port) { |server|
46
+ trap(:INT) { server.stop }
47
+ trap(:TERM) { server.stop }
48
+ }
49
+ end
50
+
51
+ def self.http_request(src, url)
52
+ url = url[1..-1].sub(/\/+/, '/')
53
+ site = Site.new(src, '')
54
+ file = site.http(url)
55
+ file and file.request
56
+ end
57
+
58
+ end
@@ -0,0 +1,142 @@
1
+ require 'fileutils'
2
+
3
+ require 'razor/template'
4
+
5
+ module Razor
6
+
7
+ class Generable
8
+
9
+ attr_reader :parent, :src_name
10
+
11
+ def initialize(parent, src_name)
12
+ @parent = parent
13
+ @src_name = src_name
14
+ end
15
+
16
+ alias dest_name src_name
17
+
18
+ def src
19
+ @src ||= File.join(parent.src, src_name)
20
+ end
21
+
22
+ def dest
23
+ @dest ||= File.join(parent.dest, dest_name)
24
+ end
25
+
26
+ def url
27
+ @url ||= File.join(parent.url, dest_name)
28
+ end
29
+
30
+ def http(url)
31
+ url.empty? and return self
32
+ return nil
33
+ end
34
+
35
+ end
36
+
37
+ class GenerableFile < Generable
38
+
39
+ def contents
40
+ File.read(src, :mode=>'rb')
41
+ end
42
+
43
+ def generate
44
+ File.open(dest, 'wb') { |f| f << contents }
45
+ end
46
+
47
+ def request
48
+ self
49
+ end
50
+
51
+ def dest_ext
52
+ File.extname(dest_name)
53
+ end
54
+ end
55
+
56
+ class Directory < Generable
57
+
58
+ attr_reader :files
59
+
60
+ def initialize(parent, src_name)
61
+ super(parent, src_name)
62
+ @files = Dir.entries(src).reject { |filename|
63
+ filename =~ /^[\._].*/ or filename=='Rakefile'
64
+ }.map { |filename|
65
+ if File.directory? File.join(src,filename)
66
+ Directory.new(self, filename)
67
+ elsif filename =~ /^[^~].*\.rb$/
68
+ TemplateFile.new(self, filename)
69
+ else
70
+ RegularFile.new(self, filename)
71
+ end
72
+ }
73
+ end
74
+
75
+ def generate
76
+ Dir.mkdir(dest)
77
+ @files.each(&:generate)
78
+ end
79
+
80
+ def http(url)
81
+ s = super(url)
82
+ s and return s
83
+ name, *rest = url.split('/')
84
+ file = @files.find { |f| f.dest_name == name }
85
+ file or return nil
86
+ file.http(rest*'/')
87
+ end
88
+
89
+ def request
90
+ @files.find { |f| f.dest_name == 'index.html' }
91
+ end
92
+ end
93
+
94
+ class Site < Directory
95
+
96
+ attr_reader :src, :dest
97
+ def initialize(src, dest)
98
+ Template.reset_instances!
99
+ @src, @dest = src, dest
100
+ layouts = File.join(src, '_layout/')
101
+ Template.path = layouts
102
+ Dir.chdir(layouts) { load './layouts.rb' }
103
+ super(nil, nil)
104
+ end
105
+
106
+ def url
107
+ '/'
108
+ end
109
+ end
110
+
111
+ class RegularFile < GenerableFile
112
+
113
+ def dest_name
114
+ # delete first '~' if needed.
115
+ super =~ /([^~].+)/
116
+ return $1
117
+ end
118
+
119
+ def generate
120
+ FileUtils.cp(src, dest)
121
+ end
122
+ end
123
+
124
+ class TemplateFile < GenerableFile
125
+
126
+ def initialize(parent, src_name)
127
+ super(parent, src_name)
128
+ @template = Template.eval(self)
129
+ end
130
+
131
+ def dest_name
132
+ ext = @template.class.get_extension
133
+ src_name.sub(/rb$/, ext)
134
+ end
135
+
136
+ def contents
137
+ @template.render
138
+ end
139
+
140
+ end
141
+
142
+ end
@@ -0,0 +1,120 @@
1
+ require 'bluecloth'
2
+ require 'sass'
3
+
4
+ module Razor
5
+
6
+ class Renderer
7
+
8
+ class Getter
9
+
10
+ class << self
11
+
12
+ attr_reader :renderers, :extensions
13
+
14
+ def define_renderer(name, renderer)
15
+ @renderers[name] = renderer
16
+ class_eval(<<-END)
17
+ def #{name}(string)
18
+ self.class.renderers[#{name.inspect}].new(string)
19
+ end
20
+ END
21
+ end
22
+
23
+ def define_extension(name, renderer)
24
+ @extensions[".#{name}"] = renderer
25
+ end
26
+
27
+ end
28
+
29
+ @renderers = {}
30
+ @extensions = {}
31
+
32
+ attr :renderer
33
+
34
+ def initialize(path, proc)
35
+ @path = path
36
+ if proc
37
+ @renderer = instance_exec &proc
38
+ else
39
+ @renderer = instance_exec { nil }
40
+ end
41
+ if @renderer.is_a? String or @renderer.is_a? NilClass
42
+ @renderer = Renderer.new(@renderer)
43
+ end
44
+ return @renderer
45
+ end
46
+
47
+ def from_file(filename)
48
+ filepath = File.join(@path, filename)
49
+ str = (File.read(filepath, :mode=>'rb') rescue nil)
50
+ ext = File.extname filename
51
+ renderer = self.class.extensions[ext]
52
+ renderer ||= Renderer
53
+ return renderer.new(str)
54
+ end
55
+
56
+ end
57
+
58
+ class << self
59
+
60
+ def get(path, proc)
61
+ Getter.new(path, proc).renderer
62
+ end
63
+
64
+ def name_ext(n)
65
+ name(n)
66
+ extension(n)
67
+ end
68
+
69
+ def name(n)
70
+ Getter.define_renderer(n, self)
71
+ end
72
+
73
+ def extension(ext)
74
+ Getter.define_extension(ext, self)
75
+ end
76
+ end
77
+
78
+ attr :string
79
+
80
+ def initialize(string)
81
+ @string = string
82
+ end
83
+
84
+ def layout_render(context)
85
+ @string.nil? and return context['yield']
86
+ render(context)
87
+ end
88
+
89
+ def valid?
90
+ !!@string
91
+ end
92
+
93
+ def render(context)
94
+ @string.nil? and return ''
95
+ Mustache.render(@string, context)
96
+ end
97
+
98
+ end
99
+
100
+ class BlueRenderer < Renderer
101
+
102
+ name_ext 'markdown'
103
+
104
+ def render(context)
105
+ BlueCloth.new(super(context)).to_html
106
+ end
107
+
108
+ end
109
+
110
+ class ScssRenderer < Renderer
111
+
112
+ name_ext 'scss'
113
+
114
+ def render(context)
115
+ Sass::Engine.new(super(context), :syntax=>:scss ).render
116
+ end
117
+
118
+ end
119
+
120
+ end
@@ -0,0 +1,82 @@
1
+ require 'optparse'
2
+ require 'highline'
3
+
4
+ require 'razor'
5
+
6
+ module Razor
7
+
8
+ HL = HighLine.new
9
+
10
+ class Runner
11
+
12
+ def initialize
13
+ @options = {}
14
+
15
+ @options_parser = OptionParser.new { |opt|
16
+
17
+ opt.banner = "Usage: razor COMMAND"
18
+
19
+ opt.separator ""
20
+ opt.separator "Commands :"
21
+ opt.separator " generate [OPTIONS] [SOURCE DESTINATION] : Generates the web directory from source."
22
+ opt.separator " server [OPTIONS] [SOURCE] : Runs a webrick server which renders page on the fly."
23
+ opt.separator ""
24
+ opt.separator "Options : "
25
+
26
+ opt.on("-p PORT", "--port PORT", "Set the local server port") do |port|
27
+ @options[:port] = port
28
+ end
29
+
30
+ opt.on_tail("-v", "--version", "Show Version") do
31
+ @options[:version] = true
32
+ end
33
+
34
+ opt.on_tail("-h", "--help", "Show this message") do
35
+ @options[:help] = true
36
+ end
37
+
38
+ opt.separator ""
39
+
40
+ }
41
+ @options_parser.parse!
42
+
43
+ unless ARGV.empty?
44
+ args = ARGV.clone
45
+ ARGV.replace []
46
+ if respond_to? args[0]
47
+ send *args
48
+ else
49
+ HL.say "Unknown Command #{args[0]}"
50
+ HL.say @options_parser.to_s
51
+ end
52
+ else
53
+ if @options[:version]
54
+ HL.say Razor::Version
55
+ else
56
+ HL.say @options_parser.to_s
57
+ end
58
+ end
59
+ end
60
+
61
+ def _check_arguments(bool)
62
+ return if bool
63
+ HL.say 'Arguments Error'
64
+ HL.say @options_parser.to_s
65
+ exit
66
+ end
67
+
68
+ def generate(*args)
69
+ _check_arguments args.size < 3
70
+ args = ['.', '_site'] if args.empty?
71
+ args << File.join(args[0], '_site') if args.size==1
72
+ Razor.generate *args
73
+ end
74
+
75
+ def server(url=nil)
76
+ url = '.' if url.nil?
77
+ Razor.server(@options[:port], url)
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,192 @@
1
+ require 'mustache'
2
+ require 'razor/renderer'
3
+
4
+ module Razor
5
+
6
+ class Template
7
+
8
+ class << self
9
+
10
+ attr_reader :definition, :playout, :instances
11
+
12
+ def inherited(subclass)
13
+ @subclasses << subclass
14
+ subclass.class_initialize
15
+ end
16
+
17
+ def class_initialize
18
+ @subclasses = []
19
+ @definition = Class.new(superclass.definition)
20
+ @playout = superclass.playout
21
+ @fields = {}
22
+ @instances = []
23
+ end
24
+
25
+ def reset_instances!
26
+ @instances = []
27
+ @subclasses.each(&:reset_instances!)
28
+ end
29
+
30
+ def eval(templatefile)
31
+ @@last_evaluated = nil
32
+ @@last_templatefile = templatefile
33
+ Kernel.eval(File.read(templatefile.src), TOPLEVEL_BINDING)
34
+ return @@last_evaluated
35
+ end
36
+
37
+ def extension(ext)
38
+ @extension = ext
39
+ end
40
+
41
+ def path=(path)
42
+ @@path = path
43
+ end
44
+
45
+ def get_extension
46
+ if superclass.respond_to? :get_extension
47
+ @extension or superclass.get_extension
48
+ else
49
+ @extension
50
+ end
51
+ end
52
+
53
+ def layout(str=nil, &block)
54
+ @playout = str ? lambda { str } : block
55
+ end
56
+
57
+ def field(name, default=nil)
58
+ if name =~ /^(field|contents)$/
59
+ raise "Try to create a #{name.inspect} field"
60
+ end
61
+ attr_accessor name
62
+ @fields["@#{name}"] = default
63
+ @definition.field(name)
64
+ end
65
+
66
+ def fields
67
+ if superclass.respond_to? :fields
68
+ superclass.fields.merge(@fields)
69
+ else
70
+ @fields
71
+ end
72
+ end
73
+
74
+ def new(*args, &block)
75
+ instance = super(*args, &block)
76
+ @instances << instance
77
+ @@last_evaluated = instance
78
+ return instance
79
+ end
80
+
81
+ def all
82
+ @subclasses.inject(@instances) { |ary, subclass|
83
+ ary + subclass.instances
84
+ }
85
+ end
86
+
87
+ def layout_render(instance)
88
+ render(Mustache::Context.new(instance))
89
+ end
90
+
91
+ def render(context)
92
+ renderer = Renderer.get(@@path, @playout)
93
+ if superclass.respond_to? :render
94
+ if renderer.valid?
95
+ context.push('yield' => renderer.layout_render(context))
96
+ end
97
+ superclass.render(context)
98
+ else
99
+ if renderer.valid?
100
+ renderer.layout_render(context)
101
+ else
102
+ context['yield']
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+
109
+ @extension = ''
110
+ @playout = nil
111
+ @fields = {}
112
+ @instances = []
113
+ @subclasses = []
114
+
115
+ attr_accessor :contents
116
+
117
+ def initialize(*args, &block)
118
+ @templatefile = @@last_templatefile
119
+ @contents = lambda { '' }
120
+ self.class.fields.each { |iv|
121
+ instance_variable_set(*iv)
122
+ }
123
+ if block_given?
124
+ self.class.definition.new(self, &block)
125
+ end
126
+ end
127
+
128
+ def url
129
+ @templatefile.url
130
+ end
131
+
132
+ def field(name, value)
133
+ (class<<self; self; end).class_eval { attr name }
134
+ instance_variable_set("@#{name}", value)
135
+ end
136
+
137
+ def yield
138
+ Renderer.get(@templatefile.parent.src, @contents).render(self)
139
+ end
140
+
141
+ def render
142
+ self.class.layout_render(self)
143
+ end
144
+
145
+ @definition = Class.new {
146
+
147
+ def self.field(name)
148
+ class_eval(<<-END)
149
+ def #{name}(val)
150
+ @tpl.#{name} = val
151
+ end
152
+ END
153
+ end
154
+
155
+ def initialize(tpl, &block)
156
+ @tpl = tpl
157
+ instance_exec &block
158
+ end
159
+
160
+ def field(name, value)
161
+ @tpl.field(name, value)
162
+ end
163
+
164
+ def contents(str=nil, &block)
165
+ @tpl.contents = str ? lambda { str } : block
166
+ end
167
+
168
+ def template_eval(&block)
169
+ @tpl.instance_eval(&block)
170
+ end
171
+
172
+ }
173
+
174
+ end
175
+
176
+ class Page < Template
177
+
178
+ extension 'html'
179
+
180
+ layout { from_file 'page.html' }
181
+
182
+ end
183
+
184
+ class StyleSheet < Template
185
+
186
+ extension 'css'
187
+
188
+ layout { from_file 'stylesheet.css' }
189
+
190
+ end
191
+
192
+ end
@@ -0,0 +1,3 @@
1
+ module Razor
2
+ Version = '0.4.0'
3
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: razor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ferreira Christopher
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-03-09 00:00:00.000000000 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: commander
17
+ requirement: &18858180 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '4'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *18858180
26
+ - !ruby/object:Gem::Dependency
27
+ name: mustache
28
+ requirement: &18857660 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *18857660
37
+ - !ruby/object:Gem::Dependency
38
+ name: rack
39
+ requirement: &18857180 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *18857180
48
+ description: ! '''Razor is a static website generator. Describe layouts and pages
49
+ in ruby. Write them with html and Mustache.
50
+
51
+ The concept behind razor is simple : layouts are described by classes, nested layouts
52
+ by subclasses and pages by instances of these classes.''
53
+
54
+ '
55
+ email: aumgn@free.fr
56
+ executables:
57
+ - razor
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - README
62
+ - LICENSE
63
+ - lib/razor.rb
64
+ - lib/razor/generable.rb
65
+ - lib/razor/runner.rb
66
+ - lib/razor/renderer.rb
67
+ - lib/razor/template.rb
68
+ - lib/version.rb
69
+ - bin/razor
70
+ has_rdoc: true
71
+ homepage: https://github.com/aumgn/razor
72
+ licenses:
73
+ - MIT License. See LICENSE file.
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 1.5.2
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Razor is a static website generator. Describe layouts and pages in ruby.
96
+ Write them with html and Mustache.
97
+ test_files: []