kcomp 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,10 +2,14 @@
2
2
 
3
3
  This is a simple command-line compiler for CodeKit .kit files for those of us who don't have it, aren't on Macs, or simply prefer the command line Usage is pretty simple:
4
4
 
5
- kcomp SRC-DIR DEST-DIR
5
+ kcomp [-s SOURCEDIR] [-d DESTDIR] [-f]
6
6
 
7
7
  if the arguemnts are omitted, they will both be assumed to be the CWD. Documentation on the .kit file format can be found at http://incident57.com/codekit/kit.php.
8
8
 
9
+ == WARNING!
10
+
11
+ This thing is hacky as hell. I started with the spec, and basically iterated until diff showed no difference between those files compiled by codekit and those compiled by this tool. I reserve every possible right to have screwed up fantastically.
12
+
9
13
  == Contributing to kcomp
10
14
 
11
15
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
data/bin/kcomp CHANGED
@@ -1,4 +1,24 @@
1
1
  #!/usr/bin/env ruby
2
2
  require File.dirname(__FILE__) + "/../lib/kcomp"
3
+ require 'optparse'
3
4
 
4
- KComp.compile! ARGV[0] || ".", ARGV[1] || "."
5
+ options = {:src => '.', :dest => '.'}
6
+
7
+ OptionParser.new do |opts|
8
+ opts.banner = "Usage: kcomp [options]"
9
+ opts.on("-s", "--source SOURCE", "The source parent directory for all .kit files") do |src|
10
+ options[:src] = src
11
+ end
12
+ opts.on("-d", "--destination DESTINATION", "The output directory") do |dest|
13
+ options[:dest] = dest
14
+ end
15
+ opts.on("-f", "--flatten", "Flatten all output in destination directory") do
16
+ options[:flatten] = true
17
+ end
18
+ opts.on_tail("-h", "--help", "Print this help message") do
19
+ puts opts
20
+ exit
21
+ end
22
+ end.parse!
23
+
24
+ KComp.compile! options[:src], options[:dest], options
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "kcomp"
8
- s.version = "0.1.1"
8
+ s.version = "0.1.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jeremy Holland"]
@@ -43,17 +43,13 @@ Gem::Specification.new do |s|
43
43
  "spec/support/test-src/_partial1.kit",
44
44
  "spec/support/test-src/_partial2.kit",
45
45
  "spec/support/test-src/_partial3.kit",
46
- "spec/support/test-src/inc1.kit",
47
46
  "spec/support/test-src/inc10.kit",
48
47
  "spec/support/test-src/inc11.kit",
49
48
  "spec/support/test-src/inc12.kit",
50
- "spec/support/test-src/inc2.kit",
51
- "spec/support/test-src/inc4.kit",
52
49
  "spec/support/test-src/inc5.kit",
53
50
  "spec/support/test-src/inc7.kit",
54
51
  "spec/support/test-src/inc8.kit",
55
52
  "spec/support/test-src/inc9.kit",
56
- "spec/support/test-src/somedir/inc3.kit",
57
53
  "spec/support/test-src/somedir/inc6.kit",
58
54
  "spec/support/test-src/test-inclusion.kit"
59
55
  ]
@@ -1,24 +1,30 @@
1
1
  require 'rgl/adjacency'
2
2
  require 'rgl/topsort'
3
3
  require 'fileutils'
4
+ require 'pry'
4
5
  require File.dirname(__FILE__) + "/errors"
5
6
 
6
7
  class KComp
7
- def initialize(src, dest)
8
+ def initialize(src, dest, opts={})
9
+ @options = opts
8
10
  @depdg = RGL::DirectedAdjacencyGraph.new
9
11
  @texts = {}
10
- @ctexts = {}
11
- @vars = {}
12
+ @compiled = []
12
13
  @src = src = src =~ /\/$/ ? src : src + "/"
14
+ if @src !~ /^[.\/]/
15
+ @src = "./" + @src
16
+ end
13
17
  @dest = dest = dest =~ /\/$/ ? dest : dest + "/"
14
- build_vertices src
18
+ if @dest !~ /^[.\/]/
19
+ @dest = "./" + @dest
20
+ end
21
+ build_vertices @src
15
22
  @vertices = @depdg.to_a
16
- build_edges src
23
+ build_edges @src
17
24
  check_for_cycles
18
25
  @tsort = @depdg.topsort_iterator
19
26
  @reversedg = @depdg.reverse
20
27
  @rtsort = @reversedg.topsort_iterator
21
- define_variables
22
28
  end
23
29
 
24
30
  def dependency_digraph
@@ -39,51 +45,60 @@ class KComp
39
45
  end
40
46
 
41
47
  private
42
- def define_variables
43
- @tsort.each do |v|
44
- rf = f = @texts[v]
45
- vars = {}
46
- f.scan(/(<!-- ?[$@]([A-Za-z_][A-Za-z0-9_\-]*) ?[ :=] *(.+) *-->)/).each do |var|
47
- vars[var[1]] = var.last.strip
48
- rf.gsub! var.first, ""
49
- end
50
- define_variables_for_vertex v, vars
51
- end
52
- end
53
48
 
54
- def define_variables_for_vertex(v, vars)
55
- @vars[v] ||= {}
56
- @vars[v].merge! vars
57
- @depdg.adjacent_vertices(v).each do |dep|
58
- define_variables_for_vertex dep, vars
59
- end
60
- end
61
-
62
- def compile_files(dest)
63
- @rtsort.each do |v|
64
- rf = f = @texts[v]
65
- f.scan(/(<!--!!! (.+) !!!-->)/).each do |import|
66
- rf.gsub! import.first, @ctexts[import.last]
67
- end
68
- f.scan(/(<!-- ?[$@]([A-Za-z_][A-Za-z0-9_\-]*) ?-->)/).each do |import|
69
- if @vars[v][import.last].nil?
70
- raise UndefinedVariableError, "Variable #{import.last} not defined."
49
+ def compile_inclusion(vertex, dest, ovars={}, inclusion=false)
50
+ vars = ovars.dup
51
+ f = @texts[vertex].dup
52
+ rf = f.dup
53
+ if (vertex !~ /_[^\/]+\.kit$/ || inclusion)
54
+ f.scan(/(<!-- *[$@]([A-Za-z0-9_][A-Za-z0-9_]*) *-->)|(<!-- ?[$@]([A-Za-z0-9_][A-Za-z0-9_]*) ?[ :=] *(.+) *-->)|(<!--!!! (.+) !!!-->)/).each do |import|
55
+ begin
56
+ if (import[0].nil? && import[2].nil?)
57
+ rf.gsub! import[5], compile_inclusion(import[6], dest, vars, true).rstrip
58
+ elsif (import[5].nil? && import[2].nil?)
59
+ rf.gsub! import[0], vars[import[1]]
60
+ else
61
+ vars[import[3]] = import[4].strip
62
+ rf.gsub!(import[2] + "\n", "")
63
+ rf.gsub!(import[2], "")
64
+ end
71
65
  end
72
- rf.gsub! import.first, @vars[v][import.last]
73
66
  end
74
- @ctexts[v] = rf.gsub(/\n+/, "\n")
75
- if (v !~ /_[^\/]+\.kit$/)
76
- filename = dest + v.gsub(@src, "").gsub(/\.kit$/, ".html")
77
- dirname = filename.gsub(/\/[^\/]+$/, "")
67
+ if (vertex !~ /_[^\/]+\.kit$/)
68
+ unless @options[:flatten]
69
+ filename = dest + vertex.gsub(@src, "").gsub(/\.kit$/, detect_format(rf))
70
+ dirname = filename.gsub(/\/[^\/]+$/, "")
71
+ else
72
+ filename = dest + vertex.gsub(/([^\/]+\/)+/, "").gsub(/\.kit$/, detect_format(rf))
73
+ dirname = filename.gsub(/\/[^\/]+$/, "")
74
+ end
78
75
  puts "Compiling #{filename}"
79
76
  unless Dir.exists?(dirname)
80
77
  FileUtils.mkdir_p dirname
81
78
  end
82
79
  File.open(filename, 'w+') do |file|
83
- file.write @ctexts[v]
80
+ file.write rf
84
81
  end
85
82
  end
86
83
  end
84
+ rf
85
+ end
86
+
87
+ def compile_files(dest)
88
+ @tsort.each do |v|
89
+ compile_inclusion(v, dest)
90
+ end
91
+ end
92
+
93
+ def detect_format(text)
94
+ case text
95
+ when /<\?php/
96
+ ".php"
97
+ when /<%=?/
98
+ ".erb"
99
+ else
100
+ ".html"
101
+ end
87
102
  end
88
103
 
89
104
  def check_for_cycles
@@ -108,11 +123,11 @@ class KComp
108
123
 
109
124
  def build_edges(src)
110
125
  @depdg.vertices.each do |v|
111
- add_edges(src, v)
126
+ add_edges(src, v, v.gsub(src, "").gsub(/\/[^\/]+$/, "") + "/")
112
127
  end
113
128
  end
114
129
 
115
- def add_edges(src, vertex)
130
+ def add_edges(src, vertex, subdir="")
116
131
  rf = f = File.read(vertex)
117
132
  f.scan(/(<!-- ?@(?:import|include) ['"]?((?:[A-Za-z0-9_\/\-.]+(?:, *)?)+)['"]? ?-->)/).each do |import|
118
133
  repl = []
@@ -121,14 +136,14 @@ class KComp
121
136
  if incl !~ /\.\w+$/
122
137
  incl = "#{incl}.kit"
123
138
  end
124
- if @vertices.include?(src + incl)
125
- match = src + incl
126
- elsif @vertices.include?(src + "_" + incl)
127
- match = src + "_" + incl
139
+ if @vertices.include?(src + subdir + incl)
140
+ match = src + subdir + incl
141
+ elsif @vertices.include?(src + subdir + incl.gsub(/\/([^\/]+)$/, "/_#{$1}"))
142
+ match = src + subdir + "_" + incl
128
143
  else
129
144
  match = @vertices.select { |v| v =~ /#{incl}$/ }.first
130
145
  if match.nil?
131
- match = @vertices.select { |v| v =~ /_#{incl}$/ }.first
146
+ match = @vertices.select { |v| v =~ /#{incl.gsub(/([^\/]+\/)+/, "")}$/ }.first
132
147
  end
133
148
  end
134
149
  if match.nil?
@@ -142,8 +157,8 @@ class KComp
142
157
  @texts[vertex] = rf
143
158
  end
144
159
 
145
- def self.compile!(src, dest)
146
- kc = KComp.new src, dest
160
+ def self.compile!(src, dest, opts={})
161
+ kc = KComp.new src, dest, opts
147
162
  kc.compile!
148
163
  end
149
164
  end
@@ -16,135 +16,20 @@ describe KComp do
16
16
  let(:comp) { KComp.new GOOD_SRC, DEST }
17
17
  let(:undef) { KComp.new UNDEFINED_VAR_SRC, DEST }
18
18
 
19
- describe "dependency_digraph" do
20
- let(:dg) { comp.dependency_digraph }
21
- let(:adjv) { dg.adjacent_vertices(GOOD_SRC + "/test-inclusion.kit") }
22
- it "should contain a node for each .kit file in the directory" do
23
- dg.should include(GOOD_SRC + "/_partial1.kit")
24
- dg.should include(GOOD_SRC + "/_partial2.kit")
25
- dg.should include(GOOD_SRC + "/_partial3.kit")
26
- dg.should include(GOOD_SRC + "/inc1.kit")
27
- dg.should include(GOOD_SRC + "/inc2.kit")
28
- dg.should include(GOOD_SRC + "/somedir/inc3.kit")
29
- dg.should include(GOOD_SRC + "/inc4.kit")
30
- dg.should include(GOOD_SRC + "/inc5.kit")
31
- dg.should include(GOOD_SRC + "/somedir/inc6.kit")
32
- dg.should include(GOOD_SRC + "/inc7.kit")
33
- dg.should include(GOOD_SRC + "/inc8.kit")
34
- dg.should include(GOOD_SRC + "/inc9.kit")
35
- dg.should include(GOOD_SRC + "/inc10.kit")
36
- dg.should include(GOOD_SRC + "/inc11.kit")
37
- dg.should include(GOOD_SRC + "/inc12.kit")
38
- dg.should include(GOOD_SRC + "/test-inclusion.kit")
39
- end
40
-
41
- it "should have directed edges indicating dependency relations" do
42
- adjv.should include(GOOD_SRC + "/_partial1.kit")
43
- adjv.should include(GOOD_SRC + "/_partial2.kit")
44
- adjv.should include(GOOD_SRC + "/inc1.kit")
45
- adjv.should include(GOOD_SRC + "/inc2.kit")
46
- adjv.should include(GOOD_SRC + "/somedir/inc3.kit")
47
- adjv.should include(GOOD_SRC + "/inc4.kit")
48
- adjv.should include(GOOD_SRC + "/inc5.kit")
49
- adjv.should include(GOOD_SRC + "/somedir/inc6.kit")
50
- adjv.should include(GOOD_SRC + "/inc7.kit")
51
- adjv.should include(GOOD_SRC + "/inc8.kit")
52
- adjv.should include(GOOD_SRC + "/inc9.kit")
53
- adjv.should include(GOOD_SRC + "/inc10.kit")
54
- end
55
-
56
- it "should not have any directed edges for undependent or indirectly dependent files" do
57
- adjv = dg.adjacent_vertices(GOOD_SRC + "/test-inclusion.kit")
58
- adjv.should_not include(GOOD_SRC + "/test-inclusion.kit")
59
- adjv.should_not include(GOOD_SRC + "/inc11.kit")
60
- adjv.should_not include(GOOD_SRC + "/inc12.kit")
61
- adjv.should_not include(GOOD_SRC + "/_partial3.kit")
62
- end
63
- end
64
-
65
- describe "reverse_dependency_digraph" do
66
- let(:dg) { comp.reverse_dependency_digraph }
67
- let(:adjv1) { dg.adjacent_vertices(GOOD_SRC + "/inc4.kit") }
68
- let(:adjv2) { dg.adjacent_vertices(GOOD_SRC + "/inc11.kit") }
69
- let(:adjv3) { dg.adjacent_vertices(GOOD_SRC + "/_partial3.kit") }
70
-
71
- it "should contain a node for each .kit file in the directory" do
72
- dg.should include(GOOD_SRC + "/_partial1.kit")
73
- dg.should include(GOOD_SRC + "/_partial2.kit")
74
- dg.should include(GOOD_SRC + "/_partial3.kit")
75
- dg.should include(GOOD_SRC + "/inc1.kit")
76
- dg.should include(GOOD_SRC + "/inc2.kit")
77
- dg.should include(GOOD_SRC + "/somedir/inc3.kit")
78
- dg.should include(GOOD_SRC + "/inc4.kit")
79
- dg.should include(GOOD_SRC + "/inc5.kit")
80
- dg.should include(GOOD_SRC + "/somedir/inc6.kit")
81
- dg.should include(GOOD_SRC + "/inc7.kit")
82
- dg.should include(GOOD_SRC + "/inc8.kit")
83
- dg.should include(GOOD_SRC + "/inc9.kit")
84
- dg.should include(GOOD_SRC + "/inc10.kit")
85
- dg.should include(GOOD_SRC + "/inc11.kit")
86
- dg.should include(GOOD_SRC + "/inc12.kit")
87
- dg.should include(GOOD_SRC + "/test-inclusion.kit")
88
- end
89
-
90
- it "should have directed edges indicating dependent relations" do
91
- adjv1.should include(GOOD_SRC + "/test-inclusion.kit")
92
- adjv2.should include(GOOD_SRC + "/inc10.kit")
93
- adjv3.should include(GOOD_SRC + "/inc10.kit")
94
- end
95
-
96
- it "should not have any directed edges for undependent or indirectly dependent files" do
97
- adjv1.should_not include(GOOD_SRC + "/inc10.kit")
98
- adjv2.should_not include(GOOD_SRC + "/test-inclusion.kit")
99
- adjv3.should_not include(GOOD_SRC + "/test-inclusion.kit")
100
- end
101
- end
102
-
103
- describe "files" do
104
- let(:files) { comp.files }
105
-
106
- it "should return an array of all .kit files" do
107
- files.should include(GOOD_SRC + "/_partial1.kit")
108
- files.should include(GOOD_SRC + "/_partial2.kit")
109
- files.should include(GOOD_SRC + "/_partial3.kit")
110
- files.should include(GOOD_SRC + "/inc1.kit")
111
- files.should include(GOOD_SRC + "/inc2.kit")
112
- files.should include(GOOD_SRC + "/somedir/inc3.kit")
113
- files.should include(GOOD_SRC + "/inc4.kit")
114
- files.should include(GOOD_SRC + "/inc5.kit")
115
- files.should include(GOOD_SRC + "/somedir/inc6.kit")
116
- files.should include(GOOD_SRC + "/inc7.kit")
117
- files.should include(GOOD_SRC + "/inc8.kit")
118
- files.should include(GOOD_SRC + "/inc9.kit")
119
- files.should include(GOOD_SRC + "/inc10.kit")
120
- files.should include(GOOD_SRC + "/inc11.kit")
121
- files.should include(GOOD_SRC + "/inc12.kit")
122
- files.should include(GOOD_SRC + "/test-inclusion.kit")
123
- end
124
-
125
- it "should order the files topologically by dependency" do
126
- files.index(GOOD_SRC + "/_partial3.kit").should > files.index(GOOD_SRC + "/inc10.kit")
127
- files.index(GOOD_SRC + "/inc11.kit").should > files.index(GOOD_SRC + "/inc10.kit")
128
- files.index(GOOD_SRC + "/_partial1.kit").should > files.index(GOOD_SRC + "/test-inclusion.kit")
129
- files.index(GOOD_SRC + "/inc10.kit").should > files.index(GOOD_SRC + "/test-inclusion.kit")
130
- end
131
- end
132
-
133
19
  describe "compile!" do
134
20
 
135
21
  it "should create any destination directories it needs (as dictated by the source directory structure)" do
136
22
  FileUtils.rm_rf DEST + "/*"
137
- capture_stdout do
138
- comp.compile!
139
- end
23
+ comp.compile!
140
24
  Dir.exists?(DEST + "/somedir").should be_true
141
25
  end
142
26
 
143
27
  it "should create a single html file for each regular kit file" do
144
- File.exists?(DEST + "/inc1.html").should be_true
145
- File.exists?(DEST + "/inc2.html").should be_true
146
- File.exists?(DEST + "/somedir/inc3.html").should be_true
147
- File.exists?(DEST + "/inc4.html").should be_true
28
+ comp.compile!
29
+ File.exists?(DEST + "/inc1.html").should be_false
30
+ File.exists?(DEST + "/inc2.html").should be_false
31
+ File.exists?(DEST + "/somedir/inc3.html").should be_false
32
+ File.exists?(DEST + "/inc4.html").should be_false
148
33
  File.exists?(DEST + "/inc5.html").should be_true
149
34
  File.exists?(DEST + "/somedir/inc6.html").should be_true
150
35
  File.exists?(DEST + "/inc7.html").should be_true
@@ -157,6 +42,7 @@ describe KComp do
157
42
  end
158
43
 
159
44
  it "should not create an html file for partials" do
45
+ comp.compile!
160
46
  File.exists?(DEST + "/partial1.html").should be_false
161
47
  File.exists?(DEST + "/partial2.html").should be_false
162
48
  File.exists?(DEST + "/partial3.html").should be_false
@@ -164,10 +50,7 @@ describe KComp do
164
50
 
165
51
  describe "generated files" do
166
52
  it "should contain any valid variable references" do
167
- File.read(DEST + "/inc1.html").should =~ /VAR 1/
168
- File.read(DEST + "/inc2.html").should =~ /VAR 2/
169
- File.read(DEST + "/somedir/inc3.html").should =~ /VAR 3/
170
- File.read(DEST + "/inc4.html").should =~ /VAR 4/
53
+ comp.compile!
171
54
  f = File.read(DEST + "/test-inclusion.html")
172
55
  f.should =~ /VAR 1/
173
56
  f.should =~ /VAR 2/
@@ -184,6 +67,7 @@ describe KComp do
184
67
  end
185
68
 
186
69
  it "should contain any inclusions" do
70
+ comp.compile!
187
71
  f = File.read(DEST + "/inc10.html")
188
72
  f.scan(/INCLUSION 11/).length.should == 1
189
73
  f.scan(/PARTIAL 3/).length.should == 1
@@ -216,11 +100,6 @@ describe KComp do
216
100
  f.scan(/VAR 12/).length.should == 1
217
101
  end
218
102
  end
219
-
220
- it "should strip out any repeated newlines" do
221
- f = File.read(DEST + "/test-inclusion.html")
222
- f.should_not =~ /\n\n+/
223
- end
224
103
  end
225
104
 
226
105
  end
@@ -229,7 +108,7 @@ describe KComp do
229
108
  describe "compile!" do
230
109
  it "should create a new KComp instance with the provided source and destination directories and delegate compilation thereto" do
231
110
  kcomp = mock('KComp')
232
- KComp.should_receive(:new).with('blah', 'hat').and_return kcomp
111
+ KComp.should_receive(:new).with('blah', 'hat', {}).and_return kcomp
233
112
  kcomp.should_receive(:compile!)
234
113
  KComp.compile!('blah', 'hat')
235
114
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kcomp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -157,17 +157,13 @@ files:
157
157
  - spec/support/test-src/_partial1.kit
158
158
  - spec/support/test-src/_partial2.kit
159
159
  - spec/support/test-src/_partial3.kit
160
- - spec/support/test-src/inc1.kit
161
160
  - spec/support/test-src/inc10.kit
162
161
  - spec/support/test-src/inc11.kit
163
162
  - spec/support/test-src/inc12.kit
164
- - spec/support/test-src/inc2.kit
165
- - spec/support/test-src/inc4.kit
166
163
  - spec/support/test-src/inc5.kit
167
164
  - spec/support/test-src/inc7.kit
168
165
  - spec/support/test-src/inc8.kit
169
166
  - spec/support/test-src/inc9.kit
170
- - spec/support/test-src/somedir/inc3.kit
171
167
  - spec/support/test-src/somedir/inc6.kit
172
168
  - spec/support/test-src/test-inclusion.kit
173
169
  homepage: http://github.com/awebneck/kcomp
@@ -185,7 +181,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
185
181
  version: '0'
186
182
  segments:
187
183
  - 0
188
- hash: 785217893617116794
184
+ hash: 2103192968802245187
189
185
  required_rubygems_version: !ruby/object:Gem::Requirement
190
186
  none: false
191
187
  requirements:
@@ -1,3 +0,0 @@
1
- INCLUSION 1
2
-
3
- <!-- @var1 -->
@@ -1,3 +0,0 @@
1
- INCLUSION 2
2
-
3
- <!--@var2-->
@@ -1,3 +0,0 @@
1
- INCLUSION 4
2
-
3
- <!--$var4-->
@@ -1,3 +0,0 @@
1
- INCLUSION 3
2
-
3
- <!-- $var3 -->