erbside 0.1.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.
@@ -0,0 +1,122 @@
1
+ module Erbside
2
+
3
+ # Metadata belongs to the project being scaffold.
4
+ #
5
+ # TODO: Support POM::Metadata
6
+ #
7
+ class Metadata
8
+
9
+ #require 'facets/ostruct'
10
+
11
+ begin
12
+ require 'pom'
13
+ rescue LoadError
14
+ end
15
+
16
+ # Project root pathname.
17
+ attr :root
18
+
19
+ #
20
+ def initialize(root=nil)
21
+ @root = self.class.root(root) || Dir.pwd
22
+
23
+ if defined?(POM)
24
+ @pom = POM::Metadata.new(@root)
25
+ else
26
+ @pom = nil
27
+ end
28
+
29
+ @cache = {} #OpenStruct.new
30
+
31
+ load_metadata # TODO: when pom supports arbitrary metadata, merge @pom and @cache into same variable.
32
+ end
33
+
34
+ #
35
+ def method_missing(s, *a)
36
+ return super unless a.empty?
37
+ if @pom
38
+ begin
39
+ @pom.__send__(s, *a)
40
+ rescue
41
+ @cache.key?(s.to_s) ? @cache[s.to_s] : nil
42
+ end
43
+ else
44
+ @cache.key?(s.to_s) ? @cache[s.to_s] : nil
45
+ end
46
+ end
47
+
48
+ # Provide metadata to hash. Some (stencil) template systems
49
+ # need the data in hash form.
50
+
51
+ def to_h
52
+ if @pom
53
+ @pom.to_h
54
+ else
55
+ @cache
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ # Load metadata. This serves as the fallback if POM is not used.
62
+
63
+ def load_metadata
64
+ Dir[File.join(metadir, '*')].each do |f|
65
+ val = File.read(f).strip
66
+ val = YAML.load(val) if val =~ /\A---/
67
+ @cache[File.basename(f)] = val
68
+ end
69
+ end
70
+
71
+ # What is project root's metadirectory?
72
+
73
+ def metadir
74
+ @metadir ||= Dir[File.join(root, '{.meta,meta}/')].first || '.meta/'
75
+ end
76
+
77
+ #def load_value(name)
78
+ # file = File.join(metadir, name)
79
+ # file = Dir[file].first
80
+ # if file && File.file?(file)
81
+ # #return erb(file).strip
82
+ # return File.read(file).strip
83
+ # end
84
+ #end
85
+
86
+ # Root directory is indicated by the presence of a +meta/+ directory,
87
+ # or +.meta/+ hidden directory.
88
+
89
+ ROOT_INDICATORS = [ '{.meta,meta}/' ]
90
+
91
+ # Locate the project's root directory. This is determined
92
+ # by ascending up the directory tree from the current position
93
+ # until the ROOT_INDICATORS is matched. Returns +nil+ if not found.
94
+
95
+ def self.root(local=Dir.pwd)
96
+ local ||= Dir.pwd
97
+ Dir.chdir(local) do
98
+ dir = nil
99
+ ROOT_INDICATORS.find do |i|
100
+ dir = locate_root_at(i)
101
+ end
102
+ dir ? Pathname.new(File.dirname(dir)) : nil
103
+ end
104
+ end
105
+
106
+ #
107
+ def self.locate_root_at(indicator)
108
+ root = nil
109
+ dir = Dir.pwd
110
+ while !root && dir != '/'
111
+ find = File.join(dir, indicator)
112
+ root = Dir.glob(find, File::FNM_CASEFOLD).first
113
+ #break if root
114
+ dir = File.dirname(dir)
115
+ end
116
+ root ? Pathname.new(root) : nil
117
+ end
118
+
119
+ end
120
+
121
+ end
122
+
@@ -0,0 +1,128 @@
1
+ module Erbside
2
+
3
+ # = Runner
4
+ #
5
+ class Runner
6
+
7
+ require 'erbside/inline'
8
+ require 'erbside/metadata'
9
+
10
+ require 'facets/kernel/ask'
11
+ require 'facets/string/tabto'
12
+
13
+
14
+ # A T T R I B U T E S
15
+
16
+ attr_accessor :files
17
+
18
+ attr_accessor :force
19
+
20
+ attr_accessor :skip
21
+
22
+ # The +output+ can be any object that responds to #<<.
23
+ attr_accessor :output
24
+
25
+ #attr_accessor :delete
26
+
27
+
28
+ # I N I T I A L I Z E
29
+
30
+ #
31
+ def initialize(files, options)
32
+ files = files || Dir["**/*#{ext_glob}"]
33
+ files = files.map do |file|
34
+ if File.directory?(file)
35
+ collect_usable_files(file)
36
+ else
37
+ file
38
+ end
39
+ end.flatten
40
+ @files = files
41
+
42
+ @force = options[:force]
43
+ @skip = options[:skip]
44
+ @output = options[:output]
45
+ #@delete = options[:delete]
46
+ end
47
+
48
+ #
49
+ def collect_usable_files(dir)
50
+ Dir[File.join(dir,"**/*#{ext_glob}")]
51
+ end
52
+
53
+ #def delete? ; @delete ; end
54
+ def force? ; @force ; end
55
+ def skip? ; @skip ; end
56
+
57
+ def debug? ; $DEBUG ; end
58
+ def trial? ; $TRIAL ; end
59
+
60
+ #
61
+ def render
62
+ files.each do |file|
63
+ render_file(file)
64
+ end
65
+ end
66
+
67
+ # Search through a file for inline templates, render and output.
68
+ def render_file(file)
69
+ parser = Inline.factory(file)
70
+
71
+ if !parser
72
+ puts " unrecognized #{file}" if $DEBUG || $TRIAL
73
+ return
74
+ end
75
+
76
+ template = parser.new(file)
77
+
78
+ if template.exist? && skip?
79
+ puts " #{template.relative_output} skipped"
80
+ else
81
+ result = template.render
82
+ if output
83
+ output << (result + "\n")
84
+ else
85
+ save(template, result)
86
+ end
87
+ end
88
+ end
89
+
90
+ #
91
+ def save(template, result)
92
+ name = template.relative_output
93
+ save = false
94
+ if trial?
95
+ puts " #{name}"
96
+ else
97
+ if template.exist?
98
+ if !template.changed?
99
+ puts " unchanged #{name}"
100
+ elsif !force?
101
+ case ask(" overwrite #{name}? ")
102
+ when 'y', 'yes'
103
+ save = true
104
+ end
105
+ else
106
+ save = true
107
+ end
108
+ else
109
+ save = true
110
+ end
111
+ end
112
+ if save
113
+ template.save
114
+ puts " written #{name}"
115
+ end
116
+ end
117
+
118
+
119
+ private
120
+
121
+ #
122
+ def ext_glob
123
+ '{' + Inline.extension_list.join(',') + '}'
124
+ end
125
+
126
+ end
127
+
128
+ end
@@ -0,0 +1,45 @@
1
+ module Syckle::Plugins
2
+
3
+ # = Erbside Generation
4
+ #
5
+ class Erbside < Service
6
+
7
+ cycle :main, :generate
8
+ cycle :site, :generate
9
+
10
+ # Make automatic?
11
+ #autorun do
12
+ # ...
13
+ #end
14
+
15
+ available do |project|
16
+ begin
17
+ require 'erbside'
18
+ true
19
+ rescue LoadError
20
+ false
21
+ end
22
+ end
23
+
24
+ #
25
+ #def safe?; @safe; end
26
+
27
+ #
28
+ def generate(options={})
29
+ options ||= {}
30
+
31
+ dir = nil # defaults to curent directory
32
+
33
+ options[:trial] = trial?
34
+ options[:debug] = debug?
35
+ options[:quiet] = quiet?
36
+ options[:force] = force?
37
+
38
+ tiller = Erbside::Runner.new(dir, options)
39
+ tiller.till
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
@@ -0,0 +1,33 @@
1
+ #require 'tmpdir'
2
+ require 'erbside'
3
+
4
+ When "Given a file named '(((.*?)))'" do |name, text|
5
+ File.open(name, 'w+'){ |f| f << text }
6
+ end
7
+
8
+ When "Rendering via the commandline" do |text|
9
+ #@result = Erbside.cli('-o', 'example.rb')
10
+ text.sub!(/^\$\s*/, '')
11
+ @result = `#{text}`
12
+ end
13
+
14
+ When "result will be" do |text|
15
+ text.strip.assert == @result.strip
16
+ end
17
+
18
+ When "The rendered result of '(((.*?)))' will be" do |file, text|
19
+ result = ""
20
+ runner = Erbside::Runner.new([file], :output=>result)
21
+ runner.render
22
+
23
+ text.strip.assert == result.strip
24
+ end
25
+
26
+
27
+ # out = File.join(@tmpdir, "fixture/inline.rb")
28
+ # system "till -f #{out}"
29
+ # expect = File.read('test/features/proofs/inline.rb')
30
+ # result = File.read(out)
31
+ #
32
+ # assert_equal(expect, result)
33
+
@@ -0,0 +1,57 @@
1
+ == Bash
2
+
3
+ === Sideline Rendering
4
+
5
+ Given a file named 'example.sh' containing:
6
+
7
+ # ordinary comment
8
+ VERSION = "?" # :erb: VERSION = "<%= 1+1 %>"
9
+
10
+ The rendered result of 'example.sh' will be:
11
+
12
+ # ordinary comment
13
+ VERSION = "2" # :erb: VERSION = "<%= 1+1 %>"
14
+
15
+ === Sideline Rendering with First Match Marker
16
+
17
+ Given a file named 'example.sh' containing:
18
+
19
+ # Script generated 200X #:erb: ^generated <%= 2009 %>
20
+
21
+ The rendered result of 'example.sh' will be:
22
+
23
+ # Script generated 2009 #:erb: ^generated <%= 2009 %>
24
+
25
+ Notice in this case we rendered a comment.
26
+
27
+ === Multiline Rendering
28
+
29
+ Given a file named 'example.sh' containing:
30
+
31
+ #:erb+1: <%= %w{z y x}.sort.join("\n") %>
32
+ blah blah blah
33
+
34
+ The rendered result of 'example.sh' will be:
35
+
36
+ #:erb+3: <%= %w{z y x}.sort.join("\n") %>
37
+ x
38
+ y
39
+ z
40
+
41
+ === Block Rendering
42
+
43
+ Given a file named 'example.sh' containing:
44
+
45
+ #=begin :erb+0:
46
+ <%= %w{a b c}.map{ |x| "#{x}!" }.join("\n") %>
47
+ #=end
48
+
49
+ The rendered result of 'example.sh' will be:
50
+
51
+ #=begin :erb+3:
52
+ <%= %w{a b c}.map{ |x| "#{x}!" }.join("\n") %>
53
+ #=end
54
+ a!
55
+ b!
56
+ c!
57
+
@@ -0,0 +1,14 @@
1
+ == Commandline Interface
2
+
3
+ Given a file named 'example.rb' containing:
4
+
5
+ example # :erb: change <%= 1+1 %>
6
+
7
+ Rendering via the commandline:
8
+
9
+ $ erbside -o example.rb
10
+
11
+ The result will be:
12
+
13
+ change 2 # :erb: change <%= 1+1 %>
14
+
@@ -0,0 +1,50 @@
1
+ == C/C++
2
+
3
+ === Sideline Example
4
+
5
+ Sideline example, where the erb comment is to the side of the
6
+ text it will replace. Given a file named 'example.c' containing:
7
+
8
+ version = "?"; // :erb: version = "<%= 1+1 %>";
9
+
10
+ The rendered result of 'example.c' will be:
11
+
12
+ version = "2"; // :erb: version = "<%= 1+1 %>";
13
+
14
+ === Multiline Example
15
+
16
+ Multi-line example, where the erb comment replaces multiple lines but
17
+ is defined by a single line. Given a file named 'example.c' containing:
18
+
19
+ void main() {
20
+ //:erb+1: <%= %w{z(); y(); x();}.sort.join("\n").indent(2) %>
21
+ will be replaced
22
+ }
23
+
24
+ The rendered result of 'example.c' will be:
25
+
26
+ void main() {
27
+ //:erb+3: <%= %w{z(); y(); x();}.sort.join("\n").indent(2) %>
28
+ x();
29
+ y();
30
+ z();
31
+ }
32
+
33
+ === Block Example
34
+
35
+ Block example, where the ERB comment replaces multiple lines and is
36
+ defined by a block comment. Given a file named 'example.c' containing:
37
+
38
+ /* :erb+0:
39
+ <%= %w{a b c}.map{ |e| "\#include <#{e}.h>" }.join("\n") %>
40
+ */
41
+
42
+ The rendered result of 'example.c' will be:
43
+
44
+ /* :erb+3:
45
+ <%= %w{a b c}.map{ |e| "\#include <#{e}.h>" }.join("\n") %>
46
+ */
47
+ #include <a.h>
48
+ #include <b.h>
49
+ #include <c.h>
50
+