erbside 0.1.0 → 0.2.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.
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
+