codnar 0.1.64

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/ChangeLog +165 -0
  2. data/LICENSE +19 -0
  3. data/README.rdoc +32 -0
  4. data/Rakefile +66 -0
  5. data/bin/codnar-split +5 -0
  6. data/bin/codnar-weave +5 -0
  7. data/codnar.html +10945 -0
  8. data/doc/logo.png +0 -0
  9. data/doc/root.html +22 -0
  10. data/doc/story.markdown +180 -0
  11. data/doc/system.markdown +671 -0
  12. data/lib/codnar.rb +41 -0
  13. data/lib/codnar/application.rb +92 -0
  14. data/lib/codnar/cache.rb +61 -0
  15. data/lib/codnar/data/contents.js +113 -0
  16. data/lib/codnar/data/control_chunks.js +44 -0
  17. data/lib/codnar/data/style.css +95 -0
  18. data/lib/codnar/data/sunlight/README.txt +4 -0
  19. data/lib/codnar/data/sunlight/css-min.js +1 -0
  20. data/lib/codnar/data/sunlight/default.css +236 -0
  21. data/lib/codnar/data/sunlight/javascript-min.js +1 -0
  22. data/lib/codnar/data/sunlight/min.js +1 -0
  23. data/lib/codnar/data/sunlight/ruby-min.js +1 -0
  24. data/lib/codnar/data/yui/README.txt +3 -0
  25. data/lib/codnar/data/yui/base.css +132 -0
  26. data/lib/codnar/data/yui/reset.css +142 -0
  27. data/lib/codnar/formatter.rb +180 -0
  28. data/lib/codnar/grouper.rb +28 -0
  29. data/lib/codnar/gvim.rb +132 -0
  30. data/lib/codnar/hash_extensions.rb +41 -0
  31. data/lib/codnar/markdown.rb +47 -0
  32. data/lib/codnar/merger.rb +138 -0
  33. data/lib/codnar/rake.rb +41 -0
  34. data/lib/codnar/rake/split_task.rb +71 -0
  35. data/lib/codnar/rake/weave_task.rb +59 -0
  36. data/lib/codnar/rdoc.rb +9 -0
  37. data/lib/codnar/reader.rb +121 -0
  38. data/lib/codnar/scanner.rb +216 -0
  39. data/lib/codnar/split.rb +58 -0
  40. data/lib/codnar/split_configurations.rb +367 -0
  41. data/lib/codnar/splitter.rb +32 -0
  42. data/lib/codnar/string_extensions.rb +25 -0
  43. data/lib/codnar/sunlight.rb +17 -0
  44. data/lib/codnar/version.rb +8 -0
  45. data/lib/codnar/weave.rb +58 -0
  46. data/lib/codnar/weave_configurations.rb +48 -0
  47. data/lib/codnar/weaver.rb +105 -0
  48. data/lib/codnar/writer.rb +38 -0
  49. data/test/cache_computations.rb +41 -0
  50. data/test/deep_merge.rb +29 -0
  51. data/test/embed_images.rb +12 -0
  52. data/test/expand_markdown.rb +27 -0
  53. data/test/expand_rdoc.rb +20 -0
  54. data/test/format_code_gvim_configurations.rb +55 -0
  55. data/test/format_code_sunlight_configurations.rb +37 -0
  56. data/test/format_comment_configurations.rb +86 -0
  57. data/test/format_lines.rb +72 -0
  58. data/test/group_lines.rb +31 -0
  59. data/test/gvim_highlight_syntax.rb +49 -0
  60. data/test/identify_chunks.rb +32 -0
  61. data/test/lib/test_with_configurations.rb +15 -0
  62. data/test/merge_lines.rb +133 -0
  63. data/test/rake_tasks.rb +38 -0
  64. data/test/read_chunks.rb +110 -0
  65. data/test/run_application.rb +56 -0
  66. data/test/run_split.rb +38 -0
  67. data/test/run_weave.rb +75 -0
  68. data/test/scan_lines.rb +78 -0
  69. data/test/split_chunk_configurations.rb +55 -0
  70. data/test/split_code.rb +109 -0
  71. data/test/split_code_configurations.rb +73 -0
  72. data/test/split_combined_configurations.rb +114 -0
  73. data/test/split_complex_comment_configurations.rb +73 -0
  74. data/test/split_documentation.rb +92 -0
  75. data/test/split_documentation_configurations.rb +97 -0
  76. data/test/split_simple_comment_configurations.rb +50 -0
  77. data/test/sunlight_highlight_syntax.rb +25 -0
  78. data/test/weave_configurations.rb +144 -0
  79. data/test/write_chunks.rb +28 -0
  80. metadata +363 -0
@@ -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
@@ -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 + "&nbsp;" + 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 = "&#8211;"; // 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
+ }