codnar 0.1.64

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 (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
+ }