codnar 0.1.64
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +165 -0
- data/LICENSE +19 -0
- data/README.rdoc +32 -0
- data/Rakefile +66 -0
- data/bin/codnar-split +5 -0
- data/bin/codnar-weave +5 -0
- data/codnar.html +10945 -0
- data/doc/logo.png +0 -0
- data/doc/root.html +22 -0
- data/doc/story.markdown +180 -0
- data/doc/system.markdown +671 -0
- data/lib/codnar.rb +41 -0
- data/lib/codnar/application.rb +92 -0
- data/lib/codnar/cache.rb +61 -0
- data/lib/codnar/data/contents.js +113 -0
- data/lib/codnar/data/control_chunks.js +44 -0
- data/lib/codnar/data/style.css +95 -0
- data/lib/codnar/data/sunlight/README.txt +4 -0
- data/lib/codnar/data/sunlight/css-min.js +1 -0
- data/lib/codnar/data/sunlight/default.css +236 -0
- data/lib/codnar/data/sunlight/javascript-min.js +1 -0
- data/lib/codnar/data/sunlight/min.js +1 -0
- data/lib/codnar/data/sunlight/ruby-min.js +1 -0
- data/lib/codnar/data/yui/README.txt +3 -0
- data/lib/codnar/data/yui/base.css +132 -0
- data/lib/codnar/data/yui/reset.css +142 -0
- data/lib/codnar/formatter.rb +180 -0
- data/lib/codnar/grouper.rb +28 -0
- data/lib/codnar/gvim.rb +132 -0
- data/lib/codnar/hash_extensions.rb +41 -0
- data/lib/codnar/markdown.rb +47 -0
- data/lib/codnar/merger.rb +138 -0
- data/lib/codnar/rake.rb +41 -0
- data/lib/codnar/rake/split_task.rb +71 -0
- data/lib/codnar/rake/weave_task.rb +59 -0
- data/lib/codnar/rdoc.rb +9 -0
- data/lib/codnar/reader.rb +121 -0
- data/lib/codnar/scanner.rb +216 -0
- data/lib/codnar/split.rb +58 -0
- data/lib/codnar/split_configurations.rb +367 -0
- data/lib/codnar/splitter.rb +32 -0
- data/lib/codnar/string_extensions.rb +25 -0
- data/lib/codnar/sunlight.rb +17 -0
- data/lib/codnar/version.rb +8 -0
- data/lib/codnar/weave.rb +58 -0
- data/lib/codnar/weave_configurations.rb +48 -0
- data/lib/codnar/weaver.rb +105 -0
- data/lib/codnar/writer.rb +38 -0
- data/test/cache_computations.rb +41 -0
- data/test/deep_merge.rb +29 -0
- data/test/embed_images.rb +12 -0
- data/test/expand_markdown.rb +27 -0
- data/test/expand_rdoc.rb +20 -0
- data/test/format_code_gvim_configurations.rb +55 -0
- data/test/format_code_sunlight_configurations.rb +37 -0
- data/test/format_comment_configurations.rb +86 -0
- data/test/format_lines.rb +72 -0
- data/test/group_lines.rb +31 -0
- data/test/gvim_highlight_syntax.rb +49 -0
- data/test/identify_chunks.rb +32 -0
- data/test/lib/test_with_configurations.rb +15 -0
- data/test/merge_lines.rb +133 -0
- data/test/rake_tasks.rb +38 -0
- data/test/read_chunks.rb +110 -0
- data/test/run_application.rb +56 -0
- data/test/run_split.rb +38 -0
- data/test/run_weave.rb +75 -0
- data/test/scan_lines.rb +78 -0
- data/test/split_chunk_configurations.rb +55 -0
- data/test/split_code.rb +109 -0
- data/test/split_code_configurations.rb +73 -0
- data/test/split_combined_configurations.rb +114 -0
- data/test/split_complex_comment_configurations.rb +73 -0
- data/test/split_documentation.rb +92 -0
- data/test/split_documentation_configurations.rb +97 -0
- data/test/split_simple_comment_configurations.rb +50 -0
- data/test/sunlight_highlight_syntax.rb +25 -0
- data/test/weave_configurations.rb +144 -0
- data/test/write_chunks.rb +28 -0
- metadata +363 -0
data/lib/codnar.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require "andand"
|
2
|
+
require "base64"
|
3
|
+
require "cgi"
|
4
|
+
require "digest/sha2"
|
5
|
+
require "erb"
|
6
|
+
require "fileutils"
|
7
|
+
require "irb"
|
8
|
+
require "rdiscount"
|
9
|
+
require "rdoc/markup/to_html"
|
10
|
+
require "tempfile"
|
11
|
+
require "yaml"
|
12
|
+
|
13
|
+
require "olag/application"
|
14
|
+
require "olag/data_files"
|
15
|
+
require "olag/errors"
|
16
|
+
require "olag/hash_struct"
|
17
|
+
require "olag/string_unindent"
|
18
|
+
|
19
|
+
require "codnar/version"
|
20
|
+
|
21
|
+
require "codnar/hash_extensions"
|
22
|
+
require "codnar/markdown"
|
23
|
+
require "codnar/rdoc"
|
24
|
+
require "codnar/string_extensions"
|
25
|
+
|
26
|
+
require "codnar/application"
|
27
|
+
require "codnar/cache"
|
28
|
+
require "codnar/formatter"
|
29
|
+
require "codnar/grouper"
|
30
|
+
require "codnar/gvim"
|
31
|
+
require "codnar/merger"
|
32
|
+
require "codnar/split"
|
33
|
+
require "codnar/reader"
|
34
|
+
require "codnar/scanner"
|
35
|
+
require "codnar/split_configurations"
|
36
|
+
require "codnar/splitter"
|
37
|
+
require "codnar/sunlight"
|
38
|
+
require "codnar/weave"
|
39
|
+
require "codnar/weave_configurations"
|
40
|
+
require "codnar/weaver"
|
41
|
+
require "codnar/writer"
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Codnar
|
2
|
+
|
3
|
+
# Base class for Codnar applications.
|
4
|
+
class Application < Olag::Application
|
5
|
+
|
6
|
+
# Create a Codnar application.
|
7
|
+
def initialize(is_test = nil)
|
8
|
+
super(is_test)
|
9
|
+
@configuration ||= {}
|
10
|
+
end
|
11
|
+
|
12
|
+
# Run the Codnar application, returning its status.
|
13
|
+
def run(&block)
|
14
|
+
super(@configuration, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
# Define Codnar application flags.
|
20
|
+
def define_flags
|
21
|
+
super
|
22
|
+
define_include_flag
|
23
|
+
define_require_flag
|
24
|
+
define_merge_flag
|
25
|
+
define_print_flag
|
26
|
+
end
|
27
|
+
|
28
|
+
# Return the application's version - that is, Codnar's version.
|
29
|
+
def version
|
30
|
+
return Codnar::VERSION
|
31
|
+
end
|
32
|
+
|
33
|
+
# Define a flag for collecting module load path directories.
|
34
|
+
def define_include_flag
|
35
|
+
@options.on("-I", "--include DIRECTORY", String, "Add directory to Ruby's load path.") do |path|
|
36
|
+
$LOAD_PATH.unshift(path)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Define a flag for loading a Ruby module. This may be needed for
|
41
|
+
# user-specified configurations to work.
|
42
|
+
def define_require_flag
|
43
|
+
@options.on("-r", "--require MODULE", String, "Load a Ruby module for user configurations.") do |path|
|
44
|
+
begin
|
45
|
+
require(path)
|
46
|
+
rescue Exception => exception
|
47
|
+
$stderr.puts("#{$0}: #{exception}")
|
48
|
+
exit(1)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Define a flag for applying (merging) a Codnar configuration.
|
54
|
+
def define_merge_flag
|
55
|
+
@options.on("-c", "--configuration NAME-or-FILE", String, "Apply a named or disk file configuration.") do |name_or_path|
|
56
|
+
loaded_configuration = load_configuration(name_or_path)
|
57
|
+
@configuration = @configuration.deep_merge(loaded_configuration)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Define a flag for printing the (merged) Codnar configuration.
|
62
|
+
def define_print_flag
|
63
|
+
@options.on("-p", "--print", "Print the merged configuration.") do |name_or_path|
|
64
|
+
puts(@configuration.to_yaml)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Load a configuration either from the available builtin data or from a
|
69
|
+
# disk file.
|
70
|
+
def load_configuration(name_or_path)
|
71
|
+
return YAML.load_file(name_or_path) if File.exist?(name_or_path)
|
72
|
+
name, *arguments = name_or_path.split(':')
|
73
|
+
value = configuration_value(name)
|
74
|
+
value = value.call(*arguments) unless Hash === value
|
75
|
+
return value
|
76
|
+
end
|
77
|
+
|
78
|
+
# Compute the value of a named built-in configuration.
|
79
|
+
def configuration_value(name)
|
80
|
+
begin
|
81
|
+
value = Configuration.const_get(name.upcase)
|
82
|
+
return value if value
|
83
|
+
rescue
|
84
|
+
value = nil
|
85
|
+
end
|
86
|
+
$stderr.puts("#{$0}: Configuration: #{name} is neither a disk file nor a known configuration")
|
87
|
+
exit(1)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/lib/codnar/cache.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Codnar
|
2
|
+
|
3
|
+
# Cache long computations in disk files.
|
4
|
+
class Cache
|
5
|
+
|
6
|
+
# Whether to recompute values even if they are cached.
|
7
|
+
attr_accessor :force_recompute
|
8
|
+
|
9
|
+
# Connect to an existing disk cache. The cache is expected to be stored in
|
10
|
+
# a directory of the specified name, which is either in the current working
|
11
|
+
# directory or in one of its parent directories.
|
12
|
+
def initialize(directory, &block)
|
13
|
+
@force_recompute = false
|
14
|
+
@computation = block
|
15
|
+
@directory = find_directory(Dir.pwd, directory)
|
16
|
+
if @directory
|
17
|
+
class <<self; alias [] :cached_computation; end
|
18
|
+
else
|
19
|
+
class <<self; alias [] :uncached_computation; end
|
20
|
+
$stderr.puts("#{$0}: Could not find cache directory: #{directory}.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Access the results of the computation for the specified input. Fetch the
|
25
|
+
# result from the cache if it is there, otherwise invoke the computation
|
26
|
+
# and store the result in the cache for the next time.
|
27
|
+
def cached_computation(input)
|
28
|
+
file = cache_file(input)
|
29
|
+
return YAML.load_file(file) if File.exists?(file) and not @force_recompute
|
30
|
+
result = @computation.call(input)
|
31
|
+
File.open(file, "w") { |file| file.write(result.to_yaml) }
|
32
|
+
return result
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return the file expected to cache the computed results for a given input,
|
36
|
+
def cache_file(input)
|
37
|
+
key = Digest.hexencode(Digest::SHA2.digest(input.to_yaml))
|
38
|
+
return @directory + "/" + key + ".yaml"
|
39
|
+
end
|
40
|
+
|
41
|
+
# Access the results of a computation for the specified input, in case we
|
42
|
+
# do not have a cache directory to look for and store the results in.
|
43
|
+
def uncached_computation(input)
|
44
|
+
return @computation.call(input)
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
# Find the path of the cache directory, search from the given working
|
50
|
+
# directory upward until finding a match.
|
51
|
+
def find_directory(working_directory, cache_directory)
|
52
|
+
directory = working_directory + "/" + cache_directory
|
53
|
+
return directory if File.exists?(directory)
|
54
|
+
parent_directory = File.dirname(working_directory)
|
55
|
+
return nil if parent_directory == working_directory
|
56
|
+
return find_directory(parent_directory, cache_directory)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
/*
|
2
|
+
* Quick-and-dirty JS for inserting a table of content inside a DIV with the id
|
3
|
+
* "contents". The table of content is a series of nested UL and LI elements,
|
4
|
+
* prefixed with an H1 containing the text "0 Contents". This H1 comes in
|
5
|
+
* addition to the single static H1 expected by HTML best practices. It looks
|
6
|
+
* "right" and should not confuse search engines etc. since they do not execute
|
7
|
+
* Javascript code.
|
8
|
+
*/
|
9
|
+
function inject_contents() {
|
10
|
+
var contents = document.getElementById("contents");
|
11
|
+
var lists = contents_lists();
|
12
|
+
contents.appendChild(contents_header()); // TRICKY: Must be done after contents_lists().
|
13
|
+
contents.appendChild(lists);
|
14
|
+
}
|
15
|
+
|
16
|
+
/*
|
17
|
+
* Create a table of contents H1.
|
18
|
+
*/
|
19
|
+
function contents_header() {
|
20
|
+
var h = document.createElement("h1");
|
21
|
+
var text = document.createTextNode("Contents");
|
22
|
+
h.appendChild(text);
|
23
|
+
return h;
|
24
|
+
}
|
25
|
+
|
26
|
+
/*
|
27
|
+
* Create nested UL/LI lists for the table of content.
|
28
|
+
*/
|
29
|
+
function contents_lists() {
|
30
|
+
var container;
|
31
|
+
var indices = [];
|
32
|
+
var h_elements = all_h_elements();
|
33
|
+
for (var e in h_elements) {
|
34
|
+
h = h_elements[e];
|
35
|
+
var level = h.tagName.substring(1, 2) - 1;
|
36
|
+
container = pop_container(container, indices, level);
|
37
|
+
container = push_container(container, indices, level);
|
38
|
+
var id = indices.join(".");
|
39
|
+
container.appendChild(list_element(id, h));
|
40
|
+
h.insertBefore(header_anchor(id), h.firstChild);
|
41
|
+
}
|
42
|
+
return pop_container(container, indices, 1);
|
43
|
+
}
|
44
|
+
|
45
|
+
/*
|
46
|
+
* Get a list of all H elements in the DOM. We skip the single H1 element;
|
47
|
+
* otherwise it would just have the index "1" which would be prefixed to all
|
48
|
+
* other headers.
|
49
|
+
*/
|
50
|
+
function all_h_elements() {
|
51
|
+
var elements = document.getElementsByTagName("*");
|
52
|
+
var h_elements = [];
|
53
|
+
for (var e in elements) {
|
54
|
+
var h = elements[e];
|
55
|
+
if (/^h[2-9]$/i.test(h.tagName)) h_elements.push(h);
|
56
|
+
}
|
57
|
+
return h_elements;
|
58
|
+
}
|
59
|
+
|
60
|
+
/*
|
61
|
+
* Pop indices (and UL containers) until reaching up to a given level.
|
62
|
+
*/
|
63
|
+
function pop_container(container, indices, level) {
|
64
|
+
while (indices.length > level) {
|
65
|
+
container = container.parentNode;
|
66
|
+
indices.pop();
|
67
|
+
}
|
68
|
+
return container;
|
69
|
+
}
|
70
|
+
|
71
|
+
/*
|
72
|
+
* Push indices (and UL containers) until reaching doen to a given level.
|
73
|
+
*/
|
74
|
+
function push_container(container, indices, level) {
|
75
|
+
while (indices.length < level) {
|
76
|
+
// TRICKY: push a 0 for the very last new level, so the ++ at the end
|
77
|
+
// will turn it into a 1.
|
78
|
+
indices.push(indices.level < level - 1);
|
79
|
+
var ul = document.createElement("ul");
|
80
|
+
if (container) {
|
81
|
+
container.appendChild(ul);
|
82
|
+
}
|
83
|
+
container = ul;
|
84
|
+
}
|
85
|
+
indices[indices.length - 1]++;
|
86
|
+
return container;
|
87
|
+
}
|
88
|
+
|
89
|
+
/*
|
90
|
+
* Create a LI for an H element with some id.
|
91
|
+
*/
|
92
|
+
function list_element(id, h) {
|
93
|
+
var a = document.createElement("a");
|
94
|
+
a.href = "#" + id;
|
95
|
+
a.innerHTML = id + " " + h.innerHTML;
|
96
|
+
var li = document.createElement("li");
|
97
|
+
li.appendChild(a);
|
98
|
+
return li;
|
99
|
+
}
|
100
|
+
|
101
|
+
/*
|
102
|
+
* Create an anchor for an H element with some id.
|
103
|
+
*/
|
104
|
+
function header_anchor(id) {
|
105
|
+
var text = document.createTextNode(id + " ");
|
106
|
+
var a = document.createElement("a");
|
107
|
+
a.id = id;
|
108
|
+
a.appendChild(text);
|
109
|
+
return a;
|
110
|
+
}
|
111
|
+
|
112
|
+
/* Only invoke it after all helper functions are defined. */
|
113
|
+
inject_contents();
|
@@ -0,0 +1,44 @@
|
|
1
|
+
/*
|
2
|
+
* Quick-and-dirty JS for inserting a "+"/"-" control for chunk visibility next
|
3
|
+
* to each chunk's name. By default, all chunks are hidden.
|
4
|
+
*/
|
5
|
+
function inject_chunk_controls() {
|
6
|
+
var name_div;
|
7
|
+
foreach_chunk_elements(function(div) {
|
8
|
+
name_div = div;
|
9
|
+
}, function(html_div) {
|
10
|
+
var control_span = document.createElement("span");
|
11
|
+
var hide = function() {
|
12
|
+
control_span.innerHTML = "+";
|
13
|
+
html_div.style.display = "none";
|
14
|
+
}
|
15
|
+
var show = function() {
|
16
|
+
control_span.innerHTML = "–"; // Vertical bar.
|
17
|
+
html_div.style.display = "block";
|
18
|
+
}
|
19
|
+
name_div.onclick = function() {
|
20
|
+
html_div.style.display == "block" ? hide() : show();
|
21
|
+
}
|
22
|
+
hide(); // Initializes html_div.style.display
|
23
|
+
control_span.className = "control chunk";
|
24
|
+
name_div.insertBefore(control_span, name_div.firstChild);
|
25
|
+
})
|
26
|
+
}
|
27
|
+
|
28
|
+
/*
|
29
|
+
* Loop on all DIV elements that contain a chunk name, or that contain chunk
|
30
|
+
* HTML. Assumes that they come in pairs - name first, HTML second.
|
31
|
+
*/
|
32
|
+
function foreach_chunk_elements(name_lambda, html_lambda) {
|
33
|
+
var div_elements = document.getElementsByTagName("div");
|
34
|
+
for (var e in div_elements) {
|
35
|
+
var div = div_elements[e];
|
36
|
+
classes = " " + div.className + " ";
|
37
|
+
if (!/ chunk /.test(classes)) continue;
|
38
|
+
if (/ name /.test(classes)) name_lambda(div);
|
39
|
+
if (/ html /.test(classes)) html_lambda(div);
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
/* Only invoke it after all helper functions are defined. */
|
44
|
+
inject_chunk_controls();
|
@@ -0,0 +1,95 @@
|
|
1
|
+
/* Margin & Padding */
|
2
|
+
|
3
|
+
div.chunk.name,
|
4
|
+
div.chunk.html,
|
5
|
+
div.chunk.containers,
|
6
|
+
div.chunk table,
|
7
|
+
div.chunk td,
|
8
|
+
div.chunk pre {
|
9
|
+
margin: 0;
|
10
|
+
padding: 0;
|
11
|
+
}
|
12
|
+
div.chunk *:last-child {
|
13
|
+
margin-bottom: 0;
|
14
|
+
}
|
15
|
+
h4, h5, h6,
|
16
|
+
div.chunk,
|
17
|
+
div.comment pre {
|
18
|
+
margin: 1em 0;
|
19
|
+
}
|
20
|
+
pre,
|
21
|
+
div.comment,
|
22
|
+
div.chunk.html {
|
23
|
+
padding: 0.33em;
|
24
|
+
}
|
25
|
+
|
26
|
+
span.control.chunk {
|
27
|
+
padding-left: 0.25em;
|
28
|
+
padding-right: 0.25em;
|
29
|
+
}
|
30
|
+
|
31
|
+
/* Table of content */
|
32
|
+
|
33
|
+
div#contents ul {
|
34
|
+
margin-top: 0;
|
35
|
+
margin-bottom: 0;
|
36
|
+
padding: 0;
|
37
|
+
}
|
38
|
+
|
39
|
+
div#contents li {
|
40
|
+
list-style-type: none;
|
41
|
+
}
|
42
|
+
|
43
|
+
/* Lists */
|
44
|
+
|
45
|
+
ul.chunk.containers {
|
46
|
+
padding: 0;
|
47
|
+
margin: 0;
|
48
|
+
display: inline;
|
49
|
+
}
|
50
|
+
ul.chunk.containers li {
|
51
|
+
display: inline;
|
52
|
+
list-style-type: none;
|
53
|
+
}
|
54
|
+
|
55
|
+
/* Borders */
|
56
|
+
|
57
|
+
pre,
|
58
|
+
span.control.chunk,
|
59
|
+
div.chunk.html {
|
60
|
+
border: 1px solid #000;
|
61
|
+
}
|
62
|
+
|
63
|
+
table.layout td.indentation,
|
64
|
+
div.chunk pre {
|
65
|
+
border: none;
|
66
|
+
}
|
67
|
+
|
68
|
+
/* Colors */
|
69
|
+
|
70
|
+
span.control.chunk,
|
71
|
+
table.layout td.html {
|
72
|
+
background-color: Beige;
|
73
|
+
}
|
74
|
+
|
75
|
+
/* Colors for GVim classes */
|
76
|
+
|
77
|
+
span.Constant { color: Crimson; }
|
78
|
+
span.Identifier { color: Teal; }
|
79
|
+
span.PreProc { color: Indigo; }
|
80
|
+
span.Special { color: Navy; }
|
81
|
+
span.Statement { color: Maroon; }
|
82
|
+
span.Type { color: Green; }
|
83
|
+
span.Comment { color: Purple; }
|
84
|
+
|
85
|
+
/* Fonts */
|
86
|
+
|
87
|
+
body {
|
88
|
+
font-family: Sans-Serif;
|
89
|
+
}
|
90
|
+
pre {
|
91
|
+
font-family: Consolas, Inconsolata, Monaco, "Courier New", Monospace;
|
92
|
+
}
|
93
|
+
div.chunk.name {
|
94
|
+
font-weight: bold;
|
95
|
+
}
|