erbside 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/.gemspec +152 -0
  2. data/.gitignore +8 -0
  3. data/.ruby +48 -0
  4. data/.yardopts +6 -0
  5. data/{HISTORY → HISTORY.rdoc} +0 -0
  6. data/MANIFEST +33 -0
  7. data/NOTICE.rdoc +32 -0
  8. data/PROFILE +6 -3
  9. data/README.rdoc +76 -0
  10. data/VERSION +1 -1
  11. data/lib/erbside.rb +6 -2
  12. data/lib/erbside/context.rb +3 -3
  13. data/lib/erbside/gemspec.rb +19 -0
  14. data/lib/erbside/inline.rb +8 -5
  15. data/lib/erbside/inline/cpp.rb +7 -0
  16. data/lib/erbside/inline/css.rb +7 -0
  17. data/lib/erbside/inline/js.rb +7 -0
  18. data/lib/erbside/metadata.rb +86 -50
  19. data/lib/erbside/runner.rb +14 -5
  20. data/main.assembly +56 -0
  21. data/{test/functional → qed}/applique/env.rb +0 -0
  22. data/{test/functional → qed}/bash.rdoc +0 -0
  23. data/{test/functional → qed}/cli.rdoc +0 -0
  24. data/{test/functional → qed}/cpp.rdoc +0 -0
  25. data/{test/functional → qed}/css.rdoc +0 -0
  26. data/{test/functional → qed}/javascript.rdoc +0 -0
  27. data/{test/functional → qed}/ruby.rdoc +0 -0
  28. data/{test/functional → qed}/sgml.rdoc +0 -0
  29. data/site/.htaccess +2 -0
  30. data/site/.rsync-filter +7 -0
  31. data/site/assets/css/highlight.css +96 -0
  32. data/site/assets/css/reset.css +19 -0
  33. data/site/assets/css/site.css +52 -0
  34. data/site/assets/img/curb.jpg +0 -0
  35. data/site/assets/img/emeraled.png +0 -0
  36. data/site/assets/img/fade.png +0 -0
  37. data/site/assets/img/fork-me.png +0 -0
  38. data/site/assets/img/icon.jpg +0 -0
  39. data/site/assets/js/highlight.js +1 -0
  40. data/site/assets/js/jquery.js +19 -0
  41. data/site/assets/js/jquery.tabs.js +1 -0
  42. data/site/index.html +229 -0
  43. data/test/{unit/fixture → fixture}/inline.rb +3 -3
  44. data/test/{unit/fixture → fixture}/inline_complex.rb +0 -0
  45. data/test/inline_test.rb +15 -0
  46. data/work/defunct/css/color.css +45 -0
  47. data/work/defunct/css/font.css +39 -0
  48. data/work/defunct/css/struct.css +51 -0
  49. data/work/defunct/inline-old/bash.rb +36 -0
  50. data/work/defunct/inline-old/cpp.rb +39 -0
  51. data/work/defunct/inline-old/css.rb +32 -0
  52. data/work/defunct/inline-old/html.rb +32 -0
  53. data/work/defunct/inline-old/js.rb +85 -0
  54. data/work/defunct/inline-old/ruby.rb +147 -0
  55. data/work/defunct/inline-old/type.rb +91 -0
  56. data/work/defunct/inline.rb +202 -0
  57. data/work/defunct/plan.rb +37 -0
  58. data/work/defunct/tiller.rb +200 -0
  59. data/work/defunct/webme/options.yml +4 -0
  60. data/work/defunct/whole.rb +221 -0
  61. data/{lib → work}/plugins/syckle/erbside.rb +0 -0
  62. data/work/radio_earth.jpg +0 -0
  63. data/yard.watchr +12 -0
  64. metadata +94 -50
  65. data/LICENSE +0 -206
  66. data/README +0 -88
  67. data/test/unit/inline_test.rb +0 -14
@@ -0,0 +1,202 @@
1
+ module Till
2
+
3
+ # = Inline Templating
4
+ #
5
+ class Inline
6
+
7
+ # R E Q U I R E M E N T S
8
+
9
+ require 'erb'
10
+ require 'tilt'
11
+ require 'till/context'
12
+
13
+
14
+ # C O N S T A N T S
15
+
16
+ # Supported templating systems.
17
+ STENCILS = %w{ .erb .liquid .mustache }
18
+
19
+
20
+ # A T T R I B U T E S
21
+
22
+ # The file to receive inline templating.
23
+ attr :file
24
+
25
+ # The extname of the file.
26
+ attr :extension
27
+
28
+ # Location of the file.
29
+ attr :location
30
+
31
+ # The rendered result.
32
+ attr :result
33
+
34
+ # Rendering context/scope.
35
+ attr :context
36
+
37
+ # Extension name of stenciling template system
38
+ # to use. This determines with templating system to use,
39
+ # such as .erb, .liquid, etc. This defaults to '.erb',
40
+ # but can be changed in the file with:
41
+ #
42
+ # # :till.stencil: <ext>
43
+ #
44
+ attr :stencil
45
+
46
+
47
+ # I N I T I A L I Z E
48
+
49
+ #
50
+ def initialize(file)
51
+ @file = file
52
+ @extension = File.extname(file)
53
+ @location = File.dirname(File.expand_path(file))
54
+
55
+ self.stencil = '.erb'
56
+
57
+ @context = Context.new(@location)
58
+ end
59
+
60
+ #
61
+ def stencil=(ext)
62
+ ext = (ext[0,1] == '.' ? ext : ".#{ext}")
63
+ raise "unsupported stencil type -- #{ext}" unless STENCILS.include?(ext)
64
+ @stencil = ext
65
+ end
66
+
67
+ #
68
+ def root
69
+ context.metadata.root
70
+ end
71
+
72
+ #
73
+ def render
74
+ render_inline(file)
75
+ end
76
+
77
+ #
78
+ def render_inline(file)
79
+ #name = file.sub(Dir.pwd+'/', '')
80
+ save = false
81
+ text = ''
82
+ lines = File.readlines(file)
83
+ i = 0
84
+ while i < lines.size
85
+ line = lines[i]
86
+ if md = /^\s*#\s*:till.stencil:(.*?)/.match(line)
87
+ self.type = md[1].strip
88
+ text << line
89
+ elsif md = /^(\s*)#(\s*):till\+(\d*):/.match(line)
90
+ temp = md.post_match
91
+ code = md.post_match
92
+ line = lines[i+=1]
93
+ while i < lines.size && line =~ /^\s*^#/
94
+ temp << line
95
+ code << line
96
+ line = lines[i+=1]
97
+ end
98
+ res = render_template(code.gsub(/^\s*#*/,'').strip)
99
+ text << md[1] + "#" + md[2] + ":till+#{res.split("\n").size}:"
100
+ text << temp
101
+ text << res
102
+ text << "\n"
103
+ save = true
104
+ i += md[3].to_i
105
+ elsif md = /^(\s*).*?(\s*#\s*:till:)/.match(line)
106
+ pm = md.post_match.strip
107
+ if pm[0,1] == '^'
108
+ pm = pm[1..-1].strip
109
+ fm = pm[0...(pm.index('<')||-1)]
110
+ ri = line.index(fm)
111
+ if ri
112
+ text << line[0...ri] + render_template(pm) + md[2] + md.post_match
113
+ else
114
+ puts "waning: skipped line #{i} no match for #{fm}"
115
+ text << line
116
+ end
117
+ else
118
+ text << md[1] + render_template(pm) + md[2] + md.post_match
119
+ end
120
+ save = true
121
+ i += 1
122
+ else
123
+ text << line
124
+ i += 1
125
+ end
126
+ end
127
+
128
+ @result = text
129
+ end
130
+
131
+ #
132
+
133
+ def render_template(text)
134
+ template = Tilt[stencil]
135
+ unless template
136
+ warn "unknown template type #{stencil}"
137
+ template = Tilt::ERBTemplate
138
+ end
139
+ render_tilt(template.new{ text })
140
+ end
141
+
142
+ #
143
+
144
+ def render_tilt(template)
145
+ Dir.chdir(location) do
146
+ template.render(@context)
147
+ end
148
+ end
149
+
150
+ #
151
+
152
+ def relative_output(dir=nil)
153
+ dir = dir || Dir.pwd
154
+ output.sub(dir+'/', '')
155
+ end
156
+
157
+ #
158
+
159
+ def exist?
160
+ File.exist?(output)
161
+ end
162
+
163
+ # Has the file changed?
164
+
165
+ def changed?
166
+ if exist?
167
+ File.read(output) != result
168
+ else
169
+ true
170
+ end
171
+ end
172
+
173
+ # Save result to file.
174
+
175
+ def save
176
+ File.open(output, 'w'){ |f| f << result }
177
+ end
178
+
179
+ # Output file (same as the input file).
180
+
181
+ def output
182
+ file
183
+ end
184
+
185
+ #
186
+
187
+ #def erb(text, file=nil)
188
+ # if file
189
+ # dir = File.dirname(file)
190
+ # Dir.chdir(dir) do
191
+ # context.erb(text)
192
+ # end
193
+ # else
194
+ # context.erb(text)
195
+ # end
196
+ #end
197
+
198
+ end
199
+
200
+ end
201
+
202
+
@@ -0,0 +1,37 @@
1
+ module Till
2
+
3
+ # = Tilling Plan
4
+ #
5
+ # A plan file is used to easily repeat a set of tills.
6
+ #
7
+ # myfile.html:
8
+ # source: templates/myfile.rdoc
9
+ # filter: erb, rdoc
10
+ #
11
+ class Plan
12
+
13
+ include Enumerable
14
+
15
+ #
16
+
17
+ def initialize(root)
18
+ file = Dir[File.join(root, '{.config,config}/till/plan.{yml,yaml}')].first
19
+ @plan = file ? YAML.load(File.new(file) : {}
20
+ end
21
+
22
+ #
23
+
24
+ def [](file)
25
+ @plan[file]
26
+ end
27
+
28
+ #
29
+
30
+ def each(&block)
31
+ @plan.each(&block)
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
@@ -0,0 +1,200 @@
1
+ require 'till/metadata'
2
+ require 'facets/kernel/ask'
3
+ require 'facets/string/tabto'
4
+ require 'erb'
5
+
6
+ module Till
7
+
8
+ # The Tiller class is used to generate files from
9
+ # embebbded ERB template files.
10
+ #
11
+ class Tiller
12
+
13
+ attr_accessor :files
14
+
15
+ attr_accessor :force
16
+
17
+ attr_accessor :skip
18
+
19
+ #attr_accessor :delete
20
+
21
+ #
22
+ def initialize(files, options)
23
+ files = files || Dir['**/*.til']
24
+ files = files.map do |file|
25
+ if File.directory?(file)
26
+ collect_usable_files(file)
27
+ else
28
+ file
29
+ end
30
+ end.flatten
31
+ @files = files
32
+ @force = options[:force]
33
+ @skip = options[:skip]
34
+ #@delete = options[:delete]
35
+ end
36
+
37
+ def collect_usable_files(dir)
38
+ Dir[File.join(dir,'**/*.{till,til,rb}')]
39
+ end
40
+
41
+ def delete? ; @delete ; end
42
+ def force? ; @force ; end
43
+ def skip? ; @skip ; end
44
+
45
+ def debug? ; $DEBUG ; end
46
+ def trial? ; $TRIAL ; end
47
+
48
+ #
49
+ #def tillfiles
50
+ # @tillfiles ||= Dir[File.join(@output, '**/*.till')].select{ |f| File.file?(f) }
51
+ #end
52
+
53
+ #
54
+ #def rubyfiles
55
+ # @rubyfiles ||= Dir[File.join(@output, '**/*.rb')].select{ |f| File.file?(f) }
56
+ #end
57
+
58
+ def till
59
+ files.each{ |file|
60
+ raise "unsupport file type -- #{file}" unless File.extname =~ /^\.(rb|til|till)$/
61
+ end
62
+
63
+ files.each do |file|
64
+ case File.extname(file)
65
+ when '.till', '.til'
66
+ till_template(file)
67
+ when '.rb'
68
+ till_inline(file)
69
+ end
70
+ end
71
+ end
72
+
73
+ # Search for till templates (*.till) and render.
74
+ #
75
+ def till_template(file)
76
+ result = erb(File.read(file))
77
+ fname = file.chomp(File.extname(file))
78
+ write(fname, result)
79
+ #rm(file) if delete? # TODO
80
+ end
81
+
82
+ # Search through Ruby files for inline till templates.
83
+ def till_inline(file)
84
+ name = file.sub(Dir.pwd+'/', '')
85
+ save = false
86
+ text = ''
87
+ lines = File.readlines(file)
88
+ i = 0
89
+ while i < lines.size
90
+ line = lines[i]
91
+ if md = /^(\s*)#(\s*):till\+(\d*):/.match(line)
92
+ temp = md.post_match
93
+ code = md.post_match
94
+ line = lines[i+=1]
95
+ while i < lines.size && line =~ /^\s*^#/
96
+ temp << line
97
+ code << line
98
+ line = lines[i+=1]
99
+ end
100
+ res = erb(code.gsub(/^\s*#*/,'').strip, file)
101
+ text << md[1] + "#" + md[2] + ":till+#{res.split("\n").size}:"
102
+ text << temp
103
+ text << res
104
+ text << "\n"
105
+ save = true
106
+ i += md[3].to_i
107
+ elsif md = /^(\s*).*?(\s*#\s*:till:)/.match(line)
108
+ pm = md.post_match.strip
109
+ if pm[0,1] == '^'
110
+ pm = pm[1..-1].strip
111
+ fm = pm[0...(pm.index('<')||-1)]
112
+ ri = line.index(fm)
113
+ if ri
114
+ text << line[0...ri] + erb(pm, file) + md[2] + md.post_match
115
+ else
116
+ puts "waning: skipped line #{i} no match for #{fm}"
117
+ text << line
118
+ end
119
+ else
120
+ text << md[1] + erb(pm, file) + md[2] + md.post_match
121
+ end
122
+ save = true
123
+ i += 1
124
+ else
125
+ text << line
126
+ i += 1
127
+ end
128
+ end
129
+
130
+ if save
131
+ write(file, text)
132
+ end
133
+ end
134
+
135
+ #
136
+ def write(fname, text)
137
+ name = fname.sub(Dir.pwd+'/', '')
138
+ if trial?
139
+ puts " #{name}"
140
+ else
141
+ if File.exist?(fname)
142
+ if skip? # TODO: skip before running erb ?
143
+ puts " skipped #{name}"
144
+ return
145
+ elsif File.read(fname) == text
146
+ puts " unchanged #{name}"
147
+ return
148
+ elsif !force?
149
+ case ask(" overwrite #{name}? ")
150
+ when 'y', 'yes'
151
+ else
152
+ return
153
+ end
154
+ end
155
+ end
156
+ File.open(fname, 'w'){ |f| f << text }
157
+ puts " written #{name}"
158
+ end
159
+ end
160
+
161
+ #
162
+ def context
163
+ @conext ||= Erb.new() #TODO: @output ?
164
+ end
165
+
166
+ def erb(text, file=nil)
167
+ if file
168
+ dir = File.dirname(file)
169
+ Dir.chdir(dir) do
170
+ context.erb(text)
171
+ end
172
+ else
173
+ context.erb(text)
174
+ end
175
+ end
176
+
177
+ # Tiller's erb context
178
+ #
179
+ class Erb
180
+
181
+ def initialize(dir=nil)
182
+ @metadata = Metadata.new(dir)
183
+ end
184
+
185
+ def method_missing(s)
186
+ @metadata.send(s)
187
+ end
188
+
189
+ # Processes through erb.
190
+ def erb(text)
191
+ erb = ERB.new(text)
192
+ erb.result(binding)
193
+ end
194
+
195
+ end#class Context
196
+
197
+ end#class Tiller
198
+
199
+ end
200
+
@@ -0,0 +1,4 @@
1
+ ---
2
+ colors:
3
+ back: green
4
+
@@ -0,0 +1,221 @@
1
+ module Till
2
+
3
+ # = Whole Template
4
+ #
5
+ class Whole
6
+
7
+ # R E Q U I R E M E N T S
8
+
9
+ # TODO: Load engines only if used?
10
+
11
+ begin ; require 'rubygems' ; rescue LoadError ; end # why?
12
+ begin ; require 'erb' ; rescue LoadError ; end
13
+ begin ; require 'redcloth' ; rescue LoadError ; end
14
+ begin ; require 'bluecloth' ; rescue LoadError ; end
15
+ begin ; require 'rdiscount' ; rescue LoadError ; end
16
+
17
+ begin
18
+ require 'liquid'
19
+ #Liquid::Template.register_filter(TemplateFilters)
20
+ rescue LoadError
21
+ end
22
+
23
+ begin
24
+ require 'haml'
25
+ #Haml::Template.options[:format] = :html5
26
+ rescue LoadError
27
+ end
28
+
29
+ begin
30
+ require 'rdoc/markup/simple_markup'
31
+ require 'rdoc/markup/simple_markup/to_html'
32
+ rescue LoadError
33
+ end
34
+
35
+ require 'tilt'
36
+
37
+ require 'till/context'
38
+
39
+
40
+ # A T T R I B U T E S
41
+
42
+ # File pathname of the template file.
43
+ attr :file
44
+
45
+ # Directory location of the template +file+.
46
+ attr :location
47
+
48
+ # Format of the template (in terms of extension names).
49
+ attr :format
50
+
51
+ # Where to save the rendered result (defaults to +file+ w/o it's extension).
52
+ # This is also often referred to as the *target*.
53
+ attr :output
54
+
55
+ # List of redering filters to processes file through (defaults to +extension+ plus +erb+).
56
+ attr :filters
57
+
58
+ # Stores the rendered result, after #render is called.
59
+ attr :result
60
+
61
+ # Body of file.
62
+ attr :content
63
+
64
+ # Context/scope of template rendering.
65
+ attr :context
66
+
67
+
68
+ # I N I T I A L I Z E
69
+
70
+ #
71
+ def initialize(file)
72
+ @file = file
73
+
74
+ case ext = File.extname(file)
75
+ when '.till', '.til'
76
+ fname = file.chomp(ext)
77
+ else
78
+ fname = file
79
+ end
80
+
81
+ #@format = File.extname(fname)
82
+ @location = File.dirname(File.expand_path(file))
83
+
84
+ text = File.read(file).rstrip
85
+
86
+ # front matter indicator
87
+ if text =~ /\A---/
88
+ text = text.sub(/---.*?\n/, '')
89
+ meta, body = *text.split(/^---/)
90
+ else
91
+ meta = nil
92
+ body = text
93
+ end
94
+
95
+ @content = body
96
+
97
+ fm = meta ? YAML.load(meta) : {}
98
+
99
+ self.filters = fm['filter'] || ['erb']
100
+
101
+ self.format = fm['format'] || File.extname(fname)
102
+
103
+ if fm['output']
104
+ self.output = fm['output']
105
+ else
106
+ self.output = fname #.chomp(extension) #+ DEFAULT_CONVERSIONS[filters.last]
107
+ end
108
+
109
+
110
+
111
+ #@context = Context.new(@location) # prime context/scope
112
+ end
113
+
114
+ #
115
+
116
+ def output=(path)
117
+ if path[0,1] == '/'
118
+ path = File.join(root, path[1..-1])
119
+ else
120
+ path = File.join(location, path)
121
+ end
122
+ @output = File.expand_path(path)
123
+ end
124
+
125
+ #
126
+
127
+ def format=(ext)
128
+ ext = ext.to_s
129
+ ext = (ext[0,1] == '.' ? ext : ".#{ext}")
130
+ case ext
131
+ when '.md'
132
+ ext = '.markdown'
133
+ when '.tt'
134
+ ext = '.textile'
135
+ end
136
+ @format = ext
137
+ end
138
+
139
+ #
140
+
141
+ def filters=(list)
142
+ @filters = [list].flatten.compact.map{ |f| f.sub(/^\./,'') }
143
+ end
144
+
145
+ #
146
+
147
+ def relative_output(dir=nil)
148
+ dir = dir || Dir.pwd
149
+ output.sub(dir+'/', '')
150
+ end
151
+
152
+ # Does the output file exist?
153
+
154
+ def exist?
155
+ File.exist?(output)
156
+ end
157
+
158
+ #
159
+
160
+ def context
161
+ @context ||= Context.new(location)
162
+ end
163
+
164
+ # TODO: maybe bring root discovery up a level or two ?
165
+
166
+ def root
167
+ context.metadata.root
168
+ end
169
+
170
+ # Render a whole template.
171
+
172
+ def render
173
+ context = Context.new(location) # prime context/scope
174
+ result = content
175
+
176
+ filters.each do |filter|
177
+ if filter == 'html' # TODO: +next+ if html format and html filter ?
178
+ engine = Tilt[format]
179
+ else
180
+ engine = Tilt[filter]
181
+ end
182
+ raise "unknown filter #{filter}" unless engine
183
+ result = Dir.chdir(location) do
184
+ engine.new{result}.render(context)
185
+ end
186
+ end
187
+ @result = result
188
+ end
189
+
190
+ # Is the current rendering different then the output file's content?
191
+ # This will call #render if it hasn't been called yet.
192
+
193
+ def changed?
194
+ render unless result
195
+ if exist?
196
+ File.read(output) != result
197
+ else
198
+ true
199
+ end
200
+ end
201
+
202
+ # Save the rendering to the output file.
203
+ # This will call #render if it hasn't been called yet.
204
+
205
+ def save
206
+ render unless result
207
+ if File.exist?(output)
208
+ mode = File.stat(output).mode
209
+ File.chmod(mode | 0000220, output)
210
+ File.open(output, 'w'){ |f| f << result }
211
+ File.chmod(mode, output)
212
+ else
213
+ File.open(output, 'w'){ |f| f << result }
214
+ File.chmod(0440, output) # change to read-only mode
215
+ end
216
+ end
217
+
218
+ end
219
+
220
+ end
221
+