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,37 @@
1
+ require "codnar"
2
+ require "olag/test"
3
+ require "test/spec"
4
+ require "test_with_configurations"
5
+
6
+ # Test built-in split code formatting configurations using Sunlight.
7
+ class TestSunlightFormatCodeConfigurations < Test::Unit::TestCase
8
+
9
+ include Test::WithConfigurations
10
+ include Test::WithErrors
11
+ include Test::WithTempfile
12
+
13
+ CODE_TEXT = <<-EOF.unindent
14
+ local = $global;
15
+ EOF
16
+
17
+ SUNLIGHT_HTML = <<-EOF.unindent.chomp
18
+ <pre class='sunlight-highlight-ruby'>
19
+ local = $global;
20
+ </pre>
21
+ EOF
22
+
23
+ def test_sunlight_code
24
+ check_split_file(CODE_TEXT,
25
+ Codnar::Configuration::CLASSIFY_SOURCE_CODE.call("ruby"),
26
+ Codnar::Configuration::FORMAT_CODE_SUNLIGHT.call("ruby")) do |path|
27
+ [ {
28
+ "name" => path,
29
+ "locations" => [ { "file" => path, "line" => 1 } ],
30
+ "containers" => [],
31
+ "contained" => [],
32
+ "html" => SUNLIGHT_HTML,
33
+ } ]
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,86 @@
1
+ require "codnar"
2
+ require "olag/test"
3
+ require "test/spec"
4
+ require "test_with_configurations"
5
+
6
+ # Test built-in split comment formatting configurations.
7
+ class TestFormatCommentsConfigurations < Test::Unit::TestCase
8
+
9
+ include Test::WithConfigurations
10
+ include Test::WithErrors
11
+ include Test::WithTempfile
12
+
13
+ COMMENT_TEXT = <<-EOF.unindent.gsub("#!", "#")
14
+ #! Comment *text*.
15
+ EOF
16
+
17
+ PRE_HTML = <<-EOF.unindent.chomp
18
+ <pre class='comment'>
19
+ Comment *text*.
20
+ </pre>
21
+ EOF
22
+
23
+ def test_pre_comments
24
+ check_any_format(PRE_HTML, Codnar::Configuration::FORMAT_PRE_COMMENTS)
25
+ end
26
+
27
+ RDOC_HTML = <<-EOF.unindent.chomp
28
+ <table class='layout'>
29
+ <tr>
30
+ <td class='indentation'>
31
+ <pre></pre>
32
+ </td>
33
+ <td class='html'>
34
+ <div class='rdoc comment markup'>
35
+ <p>
36
+ Comment <b>text</b>.
37
+ </p>
38
+ </div>
39
+ </td>
40
+ </tr>
41
+ </table>
42
+ EOF
43
+
44
+ def test_rdoc_comments
45
+ check_any_format(RDOC_HTML, Codnar::Configuration::FORMAT_RDOC_COMMENTS)
46
+ end
47
+
48
+ MARKDOWN_HTML = <<-EOF.unindent.chomp
49
+ <table class='layout'>
50
+ <tr>
51
+ <td class='indentation'>
52
+ <pre></pre>
53
+ </td>
54
+ <td class='html'>
55
+ <div class='markdown comment markup'>
56
+ <p>
57
+ Comment <em>text</em>.
58
+ </p>
59
+ </div>
60
+ </td>
61
+ </tr>
62
+ </table>
63
+ EOF
64
+
65
+ def test_markdown_comments
66
+ check_any_format(MARKDOWN_HTML, Codnar::Configuration::FORMAT_MARKDOWN_COMMENTS)
67
+ end
68
+
69
+ protected
70
+
71
+ def check_any_format(html, configuration)
72
+ check_split_file(COMMENT_TEXT,
73
+ Codnar::Configuration::CLASSIFY_SOURCE_CODE.call("any"),
74
+ Codnar::Configuration::CLASSIFY_SHELL_COMMENTS.call,
75
+ configuration) do |path|
76
+ [ {
77
+ "name" => path,
78
+ "locations" => [ { "file" => path, "line" => 1 } ],
79
+ "containers" => [],
80
+ "contained" => [],
81
+ "html" => html,
82
+ } ]
83
+ end
84
+ end
85
+
86
+ end
@@ -0,0 +1,72 @@
1
+ require "codnar"
2
+ require "olag/test"
3
+ require "test/spec"
4
+
5
+ # Test converting classified lines to HTML.
6
+ class TestFormatLines < Test::Unit::TestCase
7
+
8
+ include Test::WithErrors
9
+
10
+ alias_method :original_setup, :setup
11
+
12
+ def setup
13
+ original_setup
14
+ Codnar::Formatter.send(:public, *Codnar::Formatter.protected_instance_methods)
15
+ @formatter = Codnar::Formatter.new(@errors,
16
+ "code" => "Formatter.lines_to_pre_html(lines)",
17
+ "fail" => "TestFormatLines.fail")
18
+ end
19
+
20
+ def test_process_html_lines
21
+ lines_group = @formatter.process_lines_group([
22
+ { "kind" => "html", "number" => 1, "payload" => "foo", },
23
+ { "kind" => "html", "number" => 2, "payload" => "bar", },
24
+ { "kind" => "html", "number" => 3, "payload" => "baz", },
25
+ ])
26
+ @errors.should == []
27
+ lines_group.should == [ { "kind" => "html", "number" => 1, "payload" => "foo\nbar\nbaz" } ]
28
+ end
29
+
30
+ def test_process_unknown_lines
31
+ lines_group = @formatter.process_lines_group([
32
+ { "kind" => "unknown-kind", "number" => 1, "payload" => "<foo>", },
33
+ ])
34
+ @errors.should == [ "#{$0}: No formatter specified for lines of kind: unknown-kind" ]
35
+ lines_group.should == [ { "kind" => "html", "number" => 1,
36
+ "payload" => "<pre class='missing formatter error'>\n&lt;foo&gt;\n</pre>" } ]
37
+ end
38
+
39
+ def test_process_code_lines
40
+ lines_group = @formatter.process_lines_group([
41
+ { "kind" => "code", "number" => 1, "payload" => "<foo>", },
42
+ { "kind" => "code", "number" => 2, "payload" => "bar", },
43
+ ])
44
+ @errors.should == []
45
+ lines_group.should == [ { "kind" => "html", "number" => 1,
46
+ "payload" => "<pre>\n&lt;foo&gt;\nbar\n</pre>" } ]
47
+ end
48
+
49
+ def test_failed_formatter
50
+ lines_group = @formatter.process_lines_group([ { "kind" => "fail", "number" => 1, "payload" => "foo", } ])
51
+ @errors.size.should == 1
52
+ @errors.last.should =~ \
53
+ /#{$0}: Formatter: TestFormatLines.fail for lines of kind: fail failed with exception:.*in `fail': Reason/
54
+ lines_group.should == [ { "kind" => "html", "number" => 1,
55
+ "payload" => "<pre class='failed formatter error'>\nfoo\n</pre>" } ]
56
+ end
57
+
58
+ def test_lines_to_html
59
+ lines_group = @formatter.lines_to_html([
60
+ { "kind" => "html", "number" => 1, "payload" => "foo" },
61
+ { "kind" => "code", "number" => 2, "payload" => "<bar>" },
62
+ { "kind" => "html", "number" => 3, "payload" => "baz" },
63
+ ])
64
+ @errors.should == []
65
+ lines_group.should == "foo\n<pre>\n&lt;bar&gt;\n</pre>\nbaz"
66
+ end
67
+
68
+ def self.fail
69
+ raise "Reason"
70
+ end
71
+
72
+ end
@@ -0,0 +1,31 @@
1
+ require "codnar"
2
+ require "test/spec"
3
+
4
+ # Test grouping classified lines by their kind.
5
+ class TestGroupLines < Test::Unit::TestCase
6
+
7
+ def test_group_empty_lines
8
+ Codnar::Grouper.lines_to_groups([]).should == []
9
+ end
10
+
11
+ def test_group_one_line
12
+ Codnar::Grouper.lines_to_groups([ { "kind" => "code" } ]).should == [ [ { "kind" => "code" } ] ]
13
+ end
14
+
15
+ def test_group_lines
16
+ Codnar::Grouper.lines_to_groups([
17
+ { "kind" => "code", "line" => "0" },
18
+ { "kind" => "code", "line" => "1" },
19
+ { "kind" => "comment", "line" => "2" },
20
+ { "kind" => "code", "line" => "3" },
21
+ ]).should == [ [
22
+ { "kind" => "code", "line" => "0" },
23
+ { "kind" => "code", "line" => "1" },
24
+ ], [
25
+ { "kind" => "comment", "line" => "2" },
26
+ ], [
27
+ { "kind" => "code", "line" => "3" },
28
+ ] ]
29
+ end
30
+
31
+ end
@@ -0,0 +1,49 @@
1
+ require "codnar"
2
+ require "test/spec"
3
+
4
+ # Test highlighting syntax using GVim.
5
+ class TestGVimHighlightSyntax < Test::Unit::TestCase
6
+
7
+ def setup
8
+ Codnar::GVim.force_recompute = true
9
+ end
10
+
11
+ def teardown
12
+ Codnar::GVim.force_recompute = false
13
+ end
14
+
15
+ def test_ruby_no_css
16
+ ruby = <<-EOF.unindent
17
+ def foo
18
+ return bar = baz
19
+ end
20
+ EOF
21
+ Codnar::GVim.cached_syntax_to_html(ruby, "ruby").should == <<-EOF.unindent #! ((( html
22
+ <div class='ruby code syntax' bgcolor="#ffffff" text="#000000">
23
+ <font face="monospace">
24
+ <font color="#ff40ff">def</font>&nbsp;<font color="#00ffff">foo</font><br />
25
+ &nbsp;&nbsp;<font color="#ffff00">return</font>&nbsp;bar = baz<br />
26
+ <font color="#ff40ff">end</font><br />
27
+ </font>
28
+ </div>
29
+ EOF
30
+ #! ))) html
31
+ end
32
+
33
+ def test_ruby_css
34
+ ruby = <<-EOF.unindent
35
+ def foo
36
+ return bar = baz
37
+ end
38
+ EOF
39
+ Codnar::GVim.cached_syntax_to_html(ruby, "ruby", [ "+:let html_use_css=1" ]).should == <<-EOF.unindent #! ((( html
40
+ <pre class='ruby code syntax'>
41
+ <span class="PreProc">def</span> <span class="Identifier">foo</span>
42
+ <span class="Statement">return</span> bar = baz
43
+ <span class="PreProc">end</span>
44
+ </pre>
45
+ EOF
46
+ #! ))) html
47
+ end
48
+
49
+ end
@@ -0,0 +1,32 @@
1
+ require "codnar"
2
+ require "test/spec"
3
+
4
+ # Test converting chunk names to identifiers.
5
+ class TestIdentifyChunks < Test::Unit::TestCase
6
+
7
+ def test_lower_case_to_id
8
+ "a".to_id.should == "a"
9
+ end
10
+
11
+ def test_upper_case_to_id
12
+ "A".to_id.should == "a"
13
+ end
14
+
15
+ def test_digits_to_id
16
+ "1".to_id.should == "1"
17
+ end
18
+
19
+ def test_non_alnum_to_id
20
+ "!@-$#".to_id.should == "-"
21
+ end
22
+
23
+ def test_complex_to_id
24
+ "C# for .NET!".to_id.should == "c-for-net-"
25
+ end
26
+
27
+ def test_strip_to_id
28
+ " a ".to_id.should == "a"
29
+ end
30
+
31
+
32
+ end
@@ -0,0 +1,15 @@
1
+ # Tests with Codnar split configurations.
2
+ module Test::WithConfigurations
3
+
4
+ # Test running the Splitter with merged configurations.
5
+ def check_split_file(file_text, *configurations, &block)
6
+ configuration = configurations.inject({}) do |merged_configuration, next_configuration|
7
+ merged_configuration.deep_merge(next_configuration)
8
+ end
9
+ splitter = Codnar::Splitter.new(@errors, configuration)
10
+ chunks = splitter.chunks(path = write_tempfile("splitted", file_text))
11
+ @errors.should == []
12
+ chunks.should == yield(path)
13
+ end
14
+
15
+ end
@@ -0,0 +1,133 @@
1
+ require "codnar"
2
+ require "olag/test"
3
+ require "test/spec"
4
+
5
+ # Test merging classified lines to chunks.
6
+ class TestMergeLines < Test::Unit::TestCase
7
+
8
+ include Test::WithErrors
9
+
10
+ def test_merge_no_chunks
11
+ lines = [ { "kind" => "code", "line" => "foo", "number" => 1, "indentation" => "", "payload" => "foo" } ]
12
+ chunks = Codnar::Merger.chunks(@errors, "path", lines)
13
+ @errors.should == []
14
+ chunks.should == [ {
15
+ "name" => "path",
16
+ "locations" => [ { "file" => "path", "line" => 1 } ],
17
+ "containers" => [],
18
+ "contained" => [],
19
+ "lines" => lines
20
+ } ]
21
+ end
22
+
23
+ def test_valid_merge
24
+ chunks = Codnar::Merger.chunks(@errors, "path", VALID_LINES)
25
+ @errors.should == []
26
+ chunks.should == VALID_CHUNKS
27
+ end
28
+
29
+ VALID_LINES = [
30
+ { "kind" => "code", "number" => 1, "line" => "before top",
31
+ "indentation" => "", "payload" => "before top" },
32
+ { "kind" => "begin_chunk", "number" => 2, "line" => " {{{ top chunk",
33
+ "indentation" => " ", "payload" => "top chunk" },
34
+ { "kind" => "code", "number" => 3, "line" => " before intermediate",
35
+ "indentation" => " ", "payload" => "before intermediate" },
36
+ { "kind" => "begin_chunk", "number" => 4, "line" => " {{{ intermediate chunk",
37
+ "indentation" => " ", "payload" => "intermediate chunk" },
38
+ { "kind" => "code", "number" => 5, "line" => " before inner",
39
+ "indentation" => " ", "payload" => "before inner" },
40
+ { "kind" => "begin_chunk", "number" => 6, "line" => " {{{ inner chunk",
41
+ "indentation" => " ", "payload" => "inner chunk" },
42
+ { "kind" => "code", "number" => 7, "line" => " inner line",
43
+ "indentation" => " ", "payload" => "inner line" },
44
+ { "kind" => "end_chunk", "number" => 8, "line" => " }}} inner chunk",
45
+ "indentation" => " ", "payload" => "inner chunk" },
46
+ { "kind" => "code", "number" => 9, "line" => " after inner",
47
+ "indentation" => " ", "payload" => "after inner" },
48
+ { "kind" => "end_chunk", "number" => 10, "line" => " }}}",
49
+ "indentation" => " ", "payload" => "" },
50
+ { "kind" => "code", "number" => 11, "line" => " after intermediate",
51
+ "indentation" => " ", "payload" => "after intermediate" },
52
+ { "kind" => "end_chunk", "number" => 12, "line" => " }}} TOP CHUNK",
53
+ "indentation" => " ", "payload" => "TOP CHUNK" },
54
+ { "kind" => "code", "number" => 13, "line" => "after top",
55
+ "indentation" => "", "payload" => "after top" }
56
+ ]
57
+
58
+ VALID_CHUNKS = [
59
+ { "name" => "path",
60
+ "locations" => [ { "file" => "path", "line" => 1 } ],
61
+ "containers" => [],
62
+ "contained" => [ "top chunk" ],
63
+ "lines" => [
64
+ VALID_LINES[0].merge("indentation" => ""),
65
+ { "kind" => "nested_chunk", "number" => 2, "line" => " {{{ top chunk",
66
+ "indentation" => " ", "payload" => "top chunk" },
67
+ VALID_LINES[12].merge("indentation" => ""),
68
+ ] },
69
+ { "name" => "top chunk",
70
+ "locations" => [ { "file" => "path", "line" => 2 } ],
71
+ "containers" => [ "path" ],
72
+ "contained" => [ "intermediate chunk" ],
73
+ "lines" => [
74
+ VALID_LINES[1].merge("indentation" => ""),
75
+ VALID_LINES[2].merge("indentation" => ""),
76
+ { "kind" => "nested_chunk", "number" => 4, "line" => " {{{ intermediate chunk",
77
+ "indentation" => " ", "payload" => "intermediate chunk" },
78
+ VALID_LINES[10].merge("indentation" => ""),
79
+ VALID_LINES[11].merge("indentation" => ""),
80
+ ] },
81
+ { "name" => "intermediate chunk",
82
+ "locations" => [ { "file" => "path", "line" => 4 } ],
83
+ "containers" => [ "top chunk" ],
84
+ "contained" => [ "inner chunk" ],
85
+ "lines" => [
86
+ VALID_LINES[3].merge("indentation" => ""),
87
+ VALID_LINES[4].merge("indentation" => ""),
88
+ { "kind" => "nested_chunk", "number" => 6, "line" => " {{{ inner chunk",
89
+ "indentation" => " ", "payload" => "inner chunk" },
90
+ VALID_LINES[8].merge("indentation" => ""),
91
+ VALID_LINES[9].merge("indentation" => ""),
92
+ ] },
93
+ { "name" => "inner chunk",
94
+ "locations" => [ { "file" => "path", "line" => 6 } ],
95
+ "containers" => [ "intermediate chunk" ],
96
+ "contained" => [],
97
+ "lines" => [
98
+ VALID_LINES[5].merge("indentation" => ""),
99
+ VALID_LINES[6].merge("indentation" => ""),
100
+ VALID_LINES[7].merge("indentation" => "")
101
+ ] }
102
+ ]
103
+
104
+ def test_mismatching_end_chunk_line
105
+ lines = [
106
+ { "kind" => "begin_chunk", "number" => 1, "line" => "{{{ top chunk",
107
+ "indentation" => "", "payload" => "top chunk" },
108
+ { "kind" => "end_chunk", "number" => 2, "line" => "}}} not top chunk",
109
+ "indentation" => "", "payload" => "not top chunk" }
110
+ ]
111
+ Codnar::Merger.chunks(@errors, "path", lines)
112
+ @errors.should == [
113
+ "#{$0}: End line for chunk: not top chunk mismatches begin line for chunk: top chunk in file: path at line: 2"
114
+ ]
115
+ end
116
+
117
+ def test_missing_begin_chunk_name
118
+ lines = [
119
+ { "kind" => "begin_chunk", "number" => 1, "line" => "{{{", "indentation" => "", "payload" => "" },
120
+ { "kind" => "end_chunk", "number" => 2, "line" => "}}}", "indentation" => "", "payload" => "" }
121
+ ]
122
+ Codnar::Merger.chunks(@errors, "path", lines)
123
+ @errors.should == [ "#{$0}: Begin line for chunk with no name in file: path at line: 1" ]
124
+ end
125
+
126
+ def test_missing_end_chunk_line
127
+ lines = [ { "kind" => "begin_chunk", "number" => 1, "line" => "{{{ top chunk",
128
+ "indentation" => "", "payload" => "top chunk" } ]
129
+ Codnar::Merger.chunks(@errors, "path", lines)
130
+ @errors.should == [ "#{$0}: Missing end line for chunk: top chunk in file: path at line: 1" ]
131
+ end
132
+
133
+ end