codestock 0.1.2 → 0.1.3

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 (47) hide show
  1. data/Rakefile +1 -0
  2. data/VERSION +1 -1
  3. data/bin/cdweb +2 -2
  4. data/codestock.gemspec +56 -10
  5. data/lib/cdstk/cdstk.rb +4 -1
  6. data/lib/codestock/cdweb/app.rb +136 -0
  7. data/lib/codestock/cdweb/cli_cdweb.rb +84 -0
  8. data/lib/codestock/cdweb/config.ru +3 -0
  9. data/lib/codestock/cdweb/lib/coderay_wrapper.rb +94 -0
  10. data/lib/codestock/cdweb/lib/command.rb +67 -0
  11. data/lib/{cdweb → codestock/cdweb/lib}/database.rb +55 -28
  12. data/lib/{cdweb → codestock/cdweb/lib}/grep.rb +24 -8
  13. data/lib/codestock/cdweb/lib/mkurl.rb +56 -0
  14. data/lib/{cdweb → codestock/cdweb/lib}/query.rb +3 -4
  15. data/lib/codestock/cdweb/lib/search_contents.rb +117 -0
  16. data/lib/codestock/cdweb/lib/search_files.rb +88 -0
  17. data/lib/{cdweb → codestock/cdweb}/public/css/gren.css +16 -1
  18. data/lib/codestock/cdweb/public/images/directory.png +0 -0
  19. data/lib/codestock/cdweb/public/images/file.png +0 -0
  20. data/lib/codestock/cdweb/views/filelist.haml +14 -0
  21. data/lib/codestock/cdweb/views/help.haml +16 -0
  22. data/lib/codestock/cdweb/views/index.haml +17 -0
  23. data/lib/codestock/cdweb/views/layout.haml +33 -0
  24. data/lib/codestock/cdweb/views/search.haml +12 -0
  25. data/lib/codestock/cdweb/views/view.haml +16 -0
  26. data/test/file_assert.rb +41 -0
  27. data/test/test_coderay_wrapper.rb +22 -0
  28. data/test/test_coderay_wrapper_data.rb +91 -0
  29. data/test/test_database.rb +54 -0
  30. data/test/test_mkurl.rb +30 -0
  31. data/test/test_query.rb +54 -0
  32. metadata +52 -26
  33. data/lib/cdweb/cli_cdweb.rb +0 -54
  34. data/lib/cdweb/coderay_wrapper.rb +0 -38
  35. data/lib/cdweb/grenweb.ru +0 -35
  36. data/lib/cdweb/help.rb +0 -40
  37. data/lib/cdweb/home.rb +0 -40
  38. data/lib/cdweb/html_renderer.rb +0 -243
  39. data/lib/cdweb/searcher.rb +0 -130
  40. data/lib/cdweb/viewer.rb +0 -52
  41. data/test/test_grenweb_database.rb +0 -36
  42. data/test/test_grenweb_html_renderer.rb +0 -41
  43. data/test/test_grenweb_query.rb +0 -54
  44. data/test/test_grenweb_searcher.rb +0 -35
  45. /data/lib/{cdweb → codestock/cdweb}/public/css/coderay.css +0 -0
  46. /data/lib/{cdweb → codestock/cdweb}/public/images/gren-icon-mini.png +0 -0
  47. /data/lib/{cdweb → codestock/cdweb}/public/images/gren-icon.png +0 -0
@@ -7,31 +7,47 @@
7
7
 
8
8
  module CodeStock
9
9
  class Grep
10
- attr_reader :content
11
-
12
10
  def initialize(content)
13
- @content = content ? content.split("\n") : []
11
+ @content = content
14
12
  end
15
13
 
16
14
  MatchLineResult = Struct.new(:index, :match_datas)
17
15
 
18
- def match_lines_or(patterns)
16
+ def match_lines_and(patterns)
19
17
  result = []
20
- patternRegexps = strs2regs(patterns, true) # @todo ignoreオプションを付ける
18
+ patternRegexps = strs2regs(patterns, true)
19
+ index = 0
21
20
 
22
- @content.each_with_index do |line, index|
21
+ @content.each_line do |line|
23
22
  match_datas = []
24
23
  patternRegexps.each {|v| match_datas << v.match(line)}
25
24
 
26
- if (match_datas.any?)
25
+ if (match_datas.all?)
27
26
  result << MatchLineResult.new(index, match_datas)
28
27
  end
28
+
29
+ index += 1
29
30
  end
30
31
 
31
32
  result
32
33
  end
33
34
 
34
- def context(result, num)
35
+ def one_match_and(patterns)
36
+ patternRegexps = strs2regs(patterns, true)
37
+ index = 0
38
+
39
+ @content.each_line do |line|
40
+ match_datas = []
41
+ patternRegexps.each {|v| match_datas << v.match(line)}
42
+
43
+ if (match_datas.all?)
44
+ return MatchLineResult.new(index, match_datas)
45
+ end
46
+
47
+ index += 1
48
+ end
49
+
50
+ nil
35
51
  end
36
52
 
37
53
  private
@@ -0,0 +1,56 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief
5
+ # @author ongaeshi
6
+ # @date 2011/07/13
7
+
8
+ require 'rubygems'
9
+ require 'rack'
10
+ include Rack::Utils
11
+
12
+ module CodeStock
13
+ class Mkurl
14
+ def initialize(path, params)
15
+ @path = escape_path(path)
16
+ @params = params
17
+ end
18
+
19
+ def inherit_query_shead_offset
20
+ create_url(query_param(true, true, true))
21
+ end
22
+
23
+ def inherit_query_shead
24
+ create_url(query_param(true, true, false))
25
+ end
26
+
27
+ def inherit_shead
28
+ create_url(query_param(false, true, false))
29
+ end
30
+
31
+ private
32
+
33
+ def escape_path(src)
34
+ escape(src).gsub("%2F", '/')
35
+ end
36
+
37
+ def create_url(qp)
38
+ if (qp == "")
39
+ @path
40
+ else
41
+ "#{@path}?#{qp}"
42
+ end
43
+ end
44
+
45
+ def query_param(query_inherit, shead_inherit, offset_inherit)
46
+ qparam = []
47
+ qparam << "query=#{escape(@params[:query])}" if (query_inherit and @params[:query])
48
+ qparam << "shead=#{escape(@params[:shead])}" if (shead_inherit and @params[:shead])
49
+ qparam << "offset=#{escape(@params[:offset])}" if (offset_inherit and @params[:offset])
50
+ qparam.join('&')
51
+ end
52
+ end
53
+ end
54
+
55
+
56
+
@@ -10,17 +10,16 @@ require 'rack'
10
10
 
11
11
  module CodeStock
12
12
  class Query
13
- include Rack::Utils
14
13
  attr_reader :query_string
15
-
14
+
16
15
  OPTIONS = [
17
16
  ['package', 'p'],
18
17
  ['filepath', 'fpath', 'f'],
19
18
  ['suffix', 's'],
20
19
  ]
21
20
 
22
- def initialize(request)
23
- @query_string = unescape(request.path_info.gsub(/\A\/|\/\z/, ''))
21
+ def initialize(str)
22
+ @query_string = str
24
23
  init_hash
25
24
  parse
26
25
  end
@@ -0,0 +1,117 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief
5
+ # @author ongaeshi
6
+ # @date 2011/07/18
7
+
8
+ require 'codestock/cdweb/lib/query'
9
+ require 'codestock/cdweb/lib/grep'
10
+ require 'codestock/cdweb/lib/mkurl'
11
+
12
+ module CodeStock
13
+ class SearchContents
14
+ attr_reader :total_records
15
+ attr_reader :elapsed
16
+ attr_reader :page
17
+
18
+ DISP_NUM = 20 # 1ページの表示数
19
+ LIMIT_NUM = 50 # 最大検索ファイル数
20
+ NTH = 3 # 表示範囲
21
+
22
+ def initialize(path, params, query)
23
+ @params = params
24
+ @q = query
25
+ @page = params[:page].to_i || 0
26
+ @offset = params[:offset].to_i
27
+ fpaths = @q.fpaths
28
+ fpaths << path unless path == ""
29
+ @records, @total_records, @elapsed = Database.instance.search(@q.keywords, @q.packages, fpaths, @q.suffixs, @offset, LIMIT_NUM)
30
+ grep_contents
31
+ end
32
+
33
+ def query
34
+ @q.query_string
35
+ end
36
+
37
+ def next_offset
38
+ @offset + @next_index
39
+ end
40
+
41
+ def data_range
42
+ @offset..(next_offset - 1)
43
+ end
44
+
45
+ def html_contents
46
+ @match_records.map {|match_record| result_match_record(match_record)}.join
47
+ end
48
+
49
+ def html_pagination
50
+ return "" if @q.empty?
51
+ return "" if next_offset >= @total_records
52
+
53
+ return <<EOF
54
+ <div class='pagination'>
55
+ #{pagination_link(next_offset, "next >>")}
56
+ </div>
57
+ EOF
58
+ end
59
+
60
+ private
61
+
62
+ MatchRecord = Struct.new(:record, :match_line)
63
+
64
+ def grep_contents
65
+ @match_records = []
66
+ @next_index = @records.size
67
+
68
+ @records.each_with_index do |record, index|
69
+ grep = Grep.new(record.content)
70
+ match_line = grep.one_match_and(@q.keywords)
71
+ @match_records << MatchRecord.new(record, match_line) if match_line
72
+
73
+ if @match_records.size > DISP_NUM
74
+ @next_index = index + 1
75
+ break
76
+ end
77
+ end
78
+ end
79
+
80
+ def result_match_record(match_record)
81
+ record = match_record.record
82
+ match_line = match_record.match_line
83
+
84
+ first_index = match_line.index - NTH
85
+ last_index = match_line.index + NTH
86
+
87
+ coderay = CodeRayWrapper.new(record.content, record.shortpath, [match_line])
88
+ coderay.set_range(first_index..last_index)
89
+
90
+ <<EOS
91
+ <dt class='result-record'><a href='#{"/home/" + record_link(record) + "##{coderay.line_number_start}"}'>#{record.shortpath}</a></dt>
92
+ <dd>
93
+ #{coderay.to_html}
94
+ </dd>
95
+ EOS
96
+ end
97
+
98
+ def pagination_link(offset, label)
99
+ tmpp = @params
100
+ tmpp[:offset] = offset.to_s
101
+ href = Mkurl.new("", tmpp).inherit_query_shead_offset
102
+ pagination_span("<a href='#{href}'>#{label}</a>")
103
+ end
104
+
105
+ def pagination_span(content)
106
+ "<span class='pagination-link'>#{content}</span>\n"
107
+ end
108
+
109
+ def record_link(record) #
110
+ Mkurl.new(record.shortpath, @params).inherit_query_shead
111
+ end
112
+
113
+ end
114
+ end
115
+
116
+
117
+
@@ -0,0 +1,88 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief
5
+ # @author ongaeshi
6
+ # @date 2011/07/18
7
+
8
+ require 'codestock/cdweb/lib/query'
9
+ require 'codestock/cdweb/lib/mkurl'
10
+ require 'codestock/cdweb/lib/command'
11
+
12
+ module CodeStock
13
+ class SearchFiles
14
+ attr_reader :total_records
15
+
16
+ DISP_NUM = 100 # 1ページの表示数
17
+
18
+ def initialize(path, params, query)
19
+ @params = params
20
+ @q = query
21
+
22
+ @offset = params[:offset].to_i
23
+
24
+ fpaths = @q.fpaths
25
+ fpaths << path unless path == ""
26
+
27
+ if (fpaths.include?("*"))
28
+ @records, @total_records = Database.instance.selectAll(@offset, DISP_NUM)
29
+ else
30
+ @records, @total_records = Database.instance.search(@q.keywords, @q.packages, fpaths, @q.suffixs, @offset, DISP_NUM)
31
+ end
32
+ end
33
+
34
+ def query
35
+ @q.query_string
36
+ end
37
+
38
+ def next_offset
39
+ @offset + @records.size
40
+ end
41
+
42
+ def data_range
43
+ @offset..(next_offset - 1)
44
+ end
45
+
46
+ def html_contents
47
+ @records.map {|record| result_record(record)}.join
48
+ end
49
+
50
+ def html_pagination
51
+ return "" if @q.empty?
52
+ return "" if next_offset >= @total_records
53
+
54
+ return <<EOF
55
+ <div class='pagination'>
56
+ #{pagination_link(next_offset, "next >>")}
57
+ </div>
58
+ EOF
59
+ end
60
+
61
+ private
62
+
63
+ def pagination_link(offset, label)
64
+ tmpp = @params
65
+ tmpp[:offset] = offset.to_s
66
+ href = Mkurl.new("", tmpp).inherit_query_shead_offset
67
+ pagination_span("<a href='#{href}'>#{label}</a>")
68
+ end
69
+
70
+ def pagination_span(content)
71
+ "<span class='pagination-link'>#{content}</span>\n"
72
+ end
73
+
74
+ def result_record(record)
75
+ <<EOS
76
+ <dt class='result-file'>#{file_or_dirimg(true)}<a href='#{"/home/" + record_link(record)}'>#{record.shortpath}</a></dt>
77
+ EOS
78
+ end
79
+
80
+ def record_link(record)
81
+ Mkurl.new(record.shortpath, @params).inherit_query_shead
82
+ end
83
+
84
+ end
85
+ end
86
+
87
+
88
+
@@ -34,6 +34,10 @@ dt.result-record {
34
34
  font-size: 105%;
35
35
  }
36
36
 
37
+ dt.result-file {
38
+ font-size: 95%;
39
+ }
40
+
37
41
  div.pagination {
38
42
  background-color:#FEFFF0;
39
43
  text-align: center;
@@ -57,4 +61,15 @@ span.keyword {
57
61
 
58
62
  font.version {
59
63
  font-size: 35%;
60
- }
64
+ }
65
+
66
+ span.highlight-line {
67
+ background-color: #d0ff9c;
68
+ /* background-color: #FFFF55; */
69
+ }
70
+
71
+ a.headmenu {
72
+ font-size: 40%;
73
+ font-weight: normal;
74
+ }
75
+
@@ -0,0 +1,14 @@
1
+ .header
2
+ %h1
3
+ <a href="/"><img src="/images/gren-icon-mini.png" alt="gren-icon" border="0"/></a>
4
+ CodeStock
5
+ = create_headmenu(@path, params)
6
+
7
+ .content
8
+ = create_form(@path, params[:query], params[:shead])
9
+
10
+ .search-summary
11
+ <span class="keyword">#{topic_path(@path, params)}</span> <span class="total-entries">#{@total_records}</span>件(#{@elapsed}秒)
12
+ ~ @record_content
13
+
14
+
@@ -0,0 +1,16 @@
1
+ - @title = 'help'
2
+
3
+ .header
4
+ %h1
5
+ <a href="/"><img src="/images/gren-icon-mini.png" alt="gren-icon" border="0"/></a>
6
+ #{@title} - CodeStock
7
+
8
+ .content
9
+ .sample-code
10
+ %ol
11
+ %li キーワードで検索<br>#{link('def open')}
12
+ %li1フレーズとして検索<br>#{link('"def open"')}
13
+ %li パッケージ名で絞り込み<br>#{link('def open p:gren')}
14
+ %li ファイル名や拡張子で絞り込み<br>#{link('def open f:test s:rb')}
15
+ %li 組み合わせ<br>#{link('p:gren p:tidtools s:rb f:test assert f:cli')}
16
+
@@ -0,0 +1,17 @@
1
+ %div(align="center")
2
+ .header_home
3
+ %h1 <a href="/"><img src="/images/gren-icon.png" alt="gren-icon" border="0" height="100px"/></a> CodeStock <font class="version">#{@version}</font>
4
+
5
+ .content
6
+ %form(method="post" action="home")
7
+ %p
8
+ %input(name="query" type="text" size="60")
9
+ %input(type="submit" value="検索")
10
+
11
+ .footer_home
12
+ <a href="/home">#{@package_num}</a>のパッケージ<br>
13
+ <a href="/home?query=f:*">#{@file_num}</a>のファイル<br>
14
+ <a href="/help">ヘルプ</a> ,
15
+ <a href="http://codestock.ongaeshi.me">codestockについて</a>
16
+
17
+
@@ -0,0 +1,33 @@
1
+ !!!
2
+
3
+ %html(lang='ja')
4
+ %head
5
+ %meta(charset='utf-8')
6
+ %title= [@title, 'CodeStock'].compact.join(' - ')
7
+ %link(rel="stylesheet" href="/css/gren.css" type="text/css" media="all")
8
+ %link(rel="stylesheet" href="/css/coderay.css" type="text/css" media="all")
9
+
10
+ %body
11
+ -# %header
12
+ -# %h1 <a href=".">CodeStock</a>
13
+
14
+ != yield
15
+
16
+ %script{:type=>"text/javascript"}
17
+ var _gaq = _gaq || [];
18
+ _gaq.push(['_setAccount', 'UA-13136329-8']);
19
+ _gaq.push(['_trackPageview']);
20
+
21
+ (function() {
22
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
23
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
24
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
25
+ })();
26
+
27
+ -# %hr
28
+
29
+ -# %footer
30
+ -# %p
31
+ -# ! Develop by <a href="./contact.html">ongaeshi</a>
32
+ -# ! Powered by <a href="http://www.ruby-lang.org/">Ruby</a> #{::RUBY_VERSION},
33
+ -# ! <a href="http://www.sinatrarb.com/">Sinatra</a> #{Sinatra::VERSION}
@@ -0,0 +1,12 @@
1
+ .header
2
+ %h1
3
+ <a href="/"><img src="/images/gren-icon-mini.png" alt="gren-icon" border="0"/></a>
4
+ CodeStock
5
+ = create_headmenu(@path, params)
6
+
7
+ .content
8
+ = create_form(@path, params[:query], params[:shead])
9
+
10
+ .search-summary
11
+ <span class="keyword">#{topic_path(@path, params)}</span> <span class="total-entries">#{@total_records}</span>件中 <span class="display-range">#{@range.first} - #{@range.last}</span>件(#{@elapsed}秒)
12
+ ~ @record_content
@@ -0,0 +1,16 @@
1
+ .header
2
+ %h1
3
+ <a href="/"><img src="/images/gren-icon-mini.png" alt="gren-icon" border="0"/></a>
4
+ CodeStock
5
+ = create_headmenu(@path, params)
6
+
7
+ .content
8
+ = create_form(@path, params[:query], params[:shead])
9
+
10
+ .search-summary
11
+ <span class="keyword">#{topic_path(@path, params)}</span>(#{@elapsed}秒)
12
+ ~ @record_content
13
+
14
+
15
+
16
+
@@ -0,0 +1,41 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief ファイルテスト用アサート関数群
5
+ # @author ongaeshi
6
+ # @date 2011/06/22
7
+ #
8
+ # 以下の関数が使えます
9
+ #
10
+ # assert_diff_files(file1, file2)
11
+ #
12
+ # 二つのファイルが等しい場合はテスト成功
13
+ # 失敗した場合は二つのファイルのdiffを表示します
14
+ #
15
+ # assert_lines(s1, s2)
16
+ #
17
+ # 文字列を行単位で比較します。
18
+ #
19
+
20
+ def assert_diff_files(file1, file2)
21
+ unless (IO.read(file1) == IO.read(file2))
22
+ puts `diff -c #{file1} #{file2}`
23
+ assert_equal true, false
24
+ else
25
+ assert_equal true, true
26
+ end
27
+ end
28
+
29
+ def assert_lines(s1, s2)
30
+ a1 = s1.to_a
31
+ a2 = s2.to_a
32
+
33
+ a1.each_index do |i|
34
+ assert_equal a1[i], a2[i]
35
+ end
36
+
37
+ # s1の行数が長い時にエラーが出てしまう
38
+
39
+ assert_equal a1.size, a2.size
40
+ end
41
+
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief
5
+ # @author ongaeshi
6
+ # @date 2011/07/16
7
+
8
+ require 'test_helper'
9
+ require 'file_assert'
10
+ require 'test_coderay_wrapper_data'
11
+ require 'codestock/cdweb/lib/coderay_wrapper'
12
+
13
+ module CodeStock
14
+ class TestCodeRayWrapper < Test::Unit::TestCase
15
+ def test_basic
16
+ assert_lines JS_SHORT_HTML, CodeRayWrapper.new(JS_SHORT_CODE, "console-dir.js").to_html
17
+ assert_lines JS_HTML , CodeRayWrapper.new(JS_CODE, "console-dir.js").to_html
18
+ end
19
+ end
20
+ end
21
+
22
+
@@ -0,0 +1,91 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # @file
4
+ # @brief
5
+ # @author ongaeshi
6
+ # @date 2011/07/16
7
+
8
+ module CodeStock
9
+ JS_SHORT_CODE = <<EOF
10
+ console.dir_s = function (object, msg) {
11
+ var disp_properties = function (properties, indent, out) {
12
+ EOF
13
+
14
+ JS_SHORT_HTML = <<EOF
15
+ <table class="CodeRay"><tr>
16
+ <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
17
+ </tt>2<tt>
18
+ </tt></pre></td>
19
+ <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span id="1">console.<span class="fu">dir_s</span> = <span class="kw">function</span> (object, msg) {</span><tt>
20
+ </tt><span id="2"> <span class="kw">var</span> <span class="fu">disp_properties</span> = <span class="kw">function</span> (properties, indent, out) {</span><tt>
21
+ </tt></pre></td>
22
+ </tr></table>
23
+ EOF
24
+
25
+ JS_CODE = <<EOF
26
+ console.dir_s = function (object, msg) {
27
+ var disp_properties = function (properties, indent, out) {
28
+ for (var i = 0; i < properties.length; ++i) {
29
+ var name = properties[i][0], value = properties[i][1];
30
+
31
+ if (typeof value == "string")
32
+ value = '"' + value + '"';
33
+
34
+ out.push(indent + name + ": " + value);
35
+ }
36
+ };
37
+
38
+ var disp_funcs = function (funcs, indent, out) {
39
+ for (var i = 0; i < funcs.length; ++i) {
40
+ var name = funcs[i][0], value = funcs[i][1];
41
+ out.push(indent + name + "()");
42
+ }
43
+ };
44
+ EOF
45
+
46
+ JS_HTML = <<EOF
47
+ <table class="CodeRay"><tr>
48
+ <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
49
+ </tt>2<tt>
50
+ </tt>3<tt>
51
+ </tt>4<tt>
52
+ </tt>5<tt>
53
+ </tt>6<tt>
54
+ </tt>7<tt>
55
+ </tt>8<tt>
56
+ </tt>9<tt>
57
+ </tt>10<tt>
58
+ </tt>11<tt>
59
+ </tt>12<tt>
60
+ </tt>13<tt>
61
+ </tt>14<tt>
62
+ </tt>15<tt>
63
+ </tt>16<tt>
64
+ </tt>17<tt>
65
+ </tt>18<tt>
66
+ </tt></pre></td>
67
+ <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span id="1">console.<span class="fu">dir_s</span> = <span class="kw">function</span> (object, msg) {</span><tt>
68
+ </tt><span id="2"> <span class="kw">var</span> <span class="fu">disp_properties</span> = <span class="kw">function</span> (properties, indent, out) {</span><tt>
69
+ </tt><span id="3"> <span class="kw">for</span> (<span class="kw">var</span> i = <span class="i">0</span>; i &lt; properties.length; ++i) {</span><tt>
70
+ </tt><span id="4"> <span class="kw">var</span> name = properties[i][<span class="i">0</span>], value = properties[i][<span class="i">1</span>];</span><tt>
71
+ </tt><span id="5"></span><tt>
72
+ </tt><span id="6"> <span class="kw">if</span> (<span class="kw">typeof</span> value == <span class="s"><span class="dl">&quot;</span><span class="k">string</span><span class="dl">&quot;</span></span>)</span><tt>
73
+ </tt><span id="7"> value = <span class="s"><span class="dl">'</span><span class="k">&quot;</span><span class="dl">'</span></span> + value + <span class="s"><span class="dl">'</span><span class="k">&quot;</span><span class="dl">'</span></span>;</span><tt>
74
+ </tt><span id="8"></span><tt>
75
+ </tt><span id="9"> out.push(indent + name + <span class="s"><span class="dl">&quot;</span><span class="k">: </span><span class="dl">&quot;</span></span> + value);</span><tt>
76
+ </tt><span id="10"> }</span><tt>
77
+ </tt><span id="11"> };</span><tt>
78
+ </tt><span id="12"> </span><tt>
79
+ </tt><span id="13"> <span class="kw">var</span> <span class="fu">disp_funcs</span> = <span class="kw">function</span> (funcs, indent, out) {</span><tt>
80
+ </tt><span id="14"> <span class="kw">for</span> (<span class="kw">var</span> i = <span class="i">0</span>; i &lt; funcs.length; ++i) {</span><tt>
81
+ </tt><span id="15"> <span class="kw">var</span> name = funcs[i][<span class="i">0</span>], value = funcs[i][<span class="i">1</span>];</span><tt>
82
+ </tt><span id="16"> out.push(indent + name + <span class="s"><span class="dl">&quot;</span><span class="k">()</span><span class="dl">&quot;</span></span>);</span><tt>
83
+ </tt><span id="17"> }</span><tt>
84
+ </tt><span id="18"> };</span><tt>
85
+ </tt></pre></td>
86
+ </tr></table>
87
+ EOF
88
+
89
+ end
90
+
91
+