juli 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +26 -0
  3. data/CODE_OF_CONDUCT.md +13 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.rdoc +39 -0
  7. data/Rakefile +89 -0
  8. data/bin/console +14 -0
  9. data/bin/je +73 -0
  10. data/bin/juli +82 -0
  11. data/bin/juli_tb.rb +76 -0
  12. data/bin/setup +7 -0
  13. data/juli.gemspec +29 -0
  14. data/lib/juli.rb +21 -0
  15. data/lib/juli/absyn.rb +206 -0
  16. data/lib/juli/command.rb +180 -0
  17. data/lib/juli/command/file_entry.rb +12 -0
  18. data/lib/juli/command/recent_update.rb +52 -0
  19. data/lib/juli/command/sitemap.rb +55 -0
  20. data/lib/juli/command/tag.rb +81 -0
  21. data/lib/juli/line_parser.y +212 -0
  22. data/lib/juli/macro.rb +39 -0
  23. data/lib/juli/macro/amazon.rb +33 -0
  24. data/lib/juli/macro/jmap.rb +38 -0
  25. data/lib/juli/macro/photo.rb +161 -0
  26. data/lib/juli/macro/tag.rb +136 -0
  27. data/lib/juli/macro/template.rb +37 -0
  28. data/lib/juli/macro/template_base.rb +44 -0
  29. data/lib/juli/macro/wikipedia.rb +19 -0
  30. data/lib/juli/parser.y +360 -0
  31. data/lib/juli/template/default.html +64 -0
  32. data/lib/juli/template/facebook.html +82 -0
  33. data/lib/juli/template/je-bash-complete +42 -0
  34. data/lib/juli/template/juli.css +173 -0
  35. data/lib/juli/template/juli.js +87 -0
  36. data/lib/juli/template/locale/en.yml +10 -0
  37. data/lib/juli/template/locale/ja.yml +10 -0
  38. data/lib/juli/template/prototype.js +4320 -0
  39. data/lib/juli/template/simple.html +45 -0
  40. data/lib/juli/template/sitemap.html +78 -0
  41. data/lib/juli/template/sitemap_order_by_mtime_DESC.html +78 -0
  42. data/lib/juli/template/slidy.html +126 -0
  43. data/lib/juli/template/sourceforge.html +71 -0
  44. data/lib/juli/template/takahashi_method.html +116 -0
  45. data/lib/juli/util.rb +255 -0
  46. data/lib/juli/util/juli_i18n.rb +32 -0
  47. data/lib/juli/version.rb +3 -0
  48. data/lib/juli/visitor.rb +12 -0
  49. data/lib/juli/visitor/html.rb +462 -0
  50. data/lib/juli/visitor/html/helper.rb +97 -0
  51. data/lib/juli/visitor/html/helper/contents.rb +76 -0
  52. data/lib/juli/visitor/html/helper/fb_comments.rb +68 -0
  53. data/lib/juli/visitor/html/helper/fb_like.rb +37 -0
  54. data/lib/juli/visitor/html/tag_helper.rb +40 -0
  55. data/lib/juli/visitor/slidy.rb +39 -0
  56. data/lib/juli/visitor/takahashi_method.rb +41 -0
  57. data/lib/juli/visitor/tree.rb +135 -0
  58. data/lib/juli/wiki.rb +52 -0
  59. data/sample/protected_photo/2012-04-22/DCIM/101_PANA/P1010441.JPG +0 -0
  60. data/sample/update_public_juli.rb +71 -0
  61. data/setup.rb +1585 -0
  62. metadata +211 -0
@@ -0,0 +1,12 @@
1
+ module Juli
2
+ module Command
3
+ # used in both Juli::Command::Sitemap Juli::Command::RecentUpdate
4
+ class FileEntry
5
+ attr_accessor :path, :mtime
6
+ def initialize(path, mtime)
7
+ @path = path
8
+ @mtime = mtime
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,52 @@
1
+ module Juli::Command
2
+ # generate recent_updates.shtml which lists recent updated entries.
3
+ # The file is for server-side-include(SSI).
4
+ class RecentUpdate
5
+ include Juli::Util
6
+ include Juli::Visitor::Html::TagHelper
7
+
8
+ # define maximum file limit in order to reduce process time.
9
+ FILE_LIMIT = 20
10
+
11
+ # cache recent_update
12
+ def initialize
13
+ @file = []
14
+ Dir.chdir(juli_repo){
15
+ Dir.glob('**/*.txt'){|f|
16
+ @file << FileEntry.new(f, File.stat(f).mtime)
17
+ }
18
+ @file.sort!{|a,b| b.mtime <=> a.mtime}
19
+ }
20
+ end
21
+
22
+ def run(opts)
23
+ File.open(File.join(conf['output_top'], 'recent_update.shtml'), 'w') do |f|
24
+ f.write(gen(opts))
25
+ end
26
+ end
27
+
28
+ private
29
+ def gen(opts)
30
+ title = I18n.t('recent_updates')
31
+ content_tag(:table, :class=>'juli_recent_update') do
32
+ content_tag(:tr, content_tag(:th, title, :colspan=>2)) +
33
+ begin
34
+ result = ''
35
+ for i in 0..FILE_LIMIT-1 do
36
+ f = @file[i]
37
+ break if !f
38
+ result +=
39
+ content_tag(:tr) do
40
+ content_tag(:td) do
41
+ content_tag(:a, f.path.gsub(/.txt$/, ''),
42
+ :href=>f.path.gsub(/.txt$/, conf['ext'])) + "\n<br/>"
43
+ end +
44
+ content_tag(:td, f.mtime.strftime('%Y/%m/%d'))
45
+ end
46
+ end
47
+ result
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,55 @@
1
+ module Juli::Command
2
+ # generate sitemap.html and sitemap_order_by_mtime_DESC.html
3
+ # under $JULI_REPO
4
+ class Sitemap
5
+ include Juli::Util
6
+ include Juli::Visitor::Html::TagHelper
7
+
8
+ # cache File info
9
+ def initialize
10
+ @file = []
11
+ Dir.chdir(juli_repo){
12
+ Dir.glob('**/*.txt'){|f|
13
+ @file << FileEntry.new(f, File.stat(f).mtime)
14
+ }
15
+ }
16
+ end
17
+
18
+ def run(opts)
19
+ sitemap_sub('sitemap.html'){|files| files.sort}
20
+ sitemap_sub('sitemap_order_by_mtime_DESC.html'){|files|
21
+ files.sort{|a,b| File.stat(a).mtime <=> File.stat(b).mtime}.reverse
22
+ }
23
+ end
24
+
25
+ private
26
+ # === INPUTS
27
+ # name:: basename without extention for sitemap
28
+ # block:: sort condition
29
+ def sitemap_sub(name, &block)
30
+ Dir.chdir(juli_repo) {
31
+ outdir = File.join(conf['output_top'])
32
+ FileUtils.mkdir(outdir) if !File.directory?(outdir)
33
+ body = ''
34
+ count = 0
35
+ for textfile in yield(Dir.glob('**/*.txt')) do
36
+ count += 1
37
+ body += sprintf("<tr><td class='num'>%d</td><td><a href='%s'>%s</a></td><td>%s</td></tr>\n",
38
+ count,
39
+ textfile.gsub(/.txt$/, conf['ext']), # url
40
+ textfile.gsub(/.txt$/, ''), # label
41
+ File.stat(textfile).mtime.strftime("%Y/%m/%d %H:%M:%S"))
42
+ end
43
+
44
+ title = I18n.t('sitemap')
45
+ prototype = 'prototype.js'
46
+ javascript = 'juli.js'
47
+ stylesheet = 'juli.css'
48
+ erb = ERB.new(File.read(find_template(name)))
49
+ File.open(out_filename(name), 'w') do |f|
50
+ f.write(erb.result(binding))
51
+ end
52
+ }
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,81 @@
1
+ # coding: UTF-8
2
+
3
+ module Juli::Command
4
+ # generate _tag.shtml which shows tag-search-result HTML page.
5
+ class Tag
6
+ include Juli::Util
7
+ include Juli::Visitor::Html::TagHelper
8
+
9
+ def initialize
10
+ @tag_macro = Juli::Macro::Tag.new
11
+ end
12
+
13
+ def run(opts)
14
+ # tag list
15
+ body = content_tag(:a, '', :name=>'top').force_encoding('UTF-8') +
16
+ "<h2>#{I18n.t('tag_list')}</h2>\n".force_encoding('UTF-8')
17
+ for tag, val in @tag_macro.tag_db do
18
+ body += gen_tag_list(tag)
19
+ end
20
+ body += gen_tag_list(
21
+ Juli::Macro::Tag::NO_TAG,
22
+ I18n.t(Juli::Macro::Tag::NO_TAG))
23
+ body += "\n\n" + '<br/>'*50
24
+
25
+ # tag detail
26
+ for tag, val in @tag_macro.tag_db do
27
+ body += gen_tag_detail(tag)
28
+ end
29
+ body += gen_tag_detail(
30
+ Juli::Macro::Tag::NO_TAG,
31
+ I18n.t(Juli::Macro::Tag::NO_TAG))
32
+
33
+ title = I18n.t('tag_list')
34
+ contents = ''
35
+ prototype = 'prototype.js'
36
+ javascript = 'juli.js'
37
+ stylesheet = 'juli.css'
38
+ erb = ERB.new(File.read(find_template('simple.html')))
39
+ File.open(File.join(conf['output_top'], '_tag.shtml'), 'w') do |f|
40
+ f.write(erb.result(binding))
41
+ end
42
+ end
43
+
44
+ private
45
+ def gen_tag_list(tag, tag_label=tag)
46
+ (content_tag(:a, tag_label,
47
+ :class => sprintf("juli_tag_%02d", @tag_macro.tag_weight_ratio(tag)),
48
+ :href => "##{tag}") + ' ').force_encoding('UTF-8')
49
+ end
50
+
51
+ def gen_tag_detail(tag, tag_label=tag)
52
+ content_tag(:a, '', :name=>tag).force_encoding('UTF-8') +
53
+ content_tag(:h2, tag_label).force_encoding('UTF-8') +
54
+ '<table>' +
55
+ begin
56
+ s = ''
57
+ for page in @tag_macro.pages(@tag_macro.to_utf8(tag)) do
58
+ file = page + '.txt'
59
+ if !File.exist?(file)
60
+ # Non-exist file may occur by manual delete/rename so that
61
+ # delete the entry from tag-DB and don't produce tag entry
62
+ # from the tag-list page.
63
+ @tag_macro.delete_page(file)
64
+ next
65
+ end
66
+
67
+ page_utf8 = @tag_macro.to_utf8(page)
68
+ s += sprintf("<tr><td><a href='%s'>%s</a></td><td>%s</td></tr>\n",
69
+ page_utf8 + @tag_macro.to_utf8(conf['ext']),
70
+ page_utf8,
71
+ File.stat(file).mtime.strftime("%Y/%m/%d %H:%M"))
72
+ end
73
+ s
74
+ end +
75
+ '</table>' +
76
+ '<br/>' +
77
+ '<a href="#top">' + I18n.t('back_to_top') + '</a>' +
78
+ '<br/>'*30
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,212 @@
1
+ # Text *line* parser for Juli format.
2
+ class Juli::LineParser
3
+ options no_result_var
4
+
5
+ rule
6
+ line
7
+ : elements { @root = val[0] }
8
+
9
+ elements
10
+ : /* none */ { LineAbsyn::ArrayNode.new }
11
+ | elements element { val[0].add(val[1]) }
12
+
13
+ element
14
+ : STRING { LineAbsyn::StringNode.new(val[0]) }
15
+ | WIKINAME { LineAbsyn::WikiName.new(val[0]) }
16
+ | TAG { LineAbsyn::StringNode.new(val[0]) }
17
+ | URL { LineAbsyn::Url.new(val[0]) }
18
+ | MACRO { LineAbsyn::Macro.new(val[0][0], val[0][1]) }
19
+ end
20
+ ---- header
21
+ module Juli::LineAbsyn
22
+ class Node
23
+ def accept(visitor)
24
+ visitor.visit_node(self)
25
+ end
26
+ end
27
+
28
+ class StringNode < Node
29
+ attr_accessor :str
30
+
31
+ def initialize(str)
32
+ @str = str
33
+ end
34
+
35
+ def accept(visitor)
36
+ visitor.visit_string(self)
37
+ end
38
+ end
39
+
40
+ class WikiName < StringNode
41
+ def accept(visitor)
42
+ visitor.visit_wikiname(self)
43
+ end
44
+ end
45
+
46
+ class Url < StringNode
47
+ def accept(visitor)
48
+ visitor.visit_url(self)
49
+ end
50
+ end
51
+
52
+ class Macro < Node
53
+ attr_accessor :name, :rest
54
+
55
+ def initialize(name, rest)
56
+ @name = name
57
+ @rest = rest
58
+ end
59
+
60
+ def accept(visitor)
61
+ visitor.visit_macro(self)
62
+ end
63
+ end
64
+
65
+ class ArrayNode < Node
66
+ attr_accessor :array
67
+
68
+ def initialize
69
+ @array = Array.new
70
+ end
71
+
72
+ def add(child)
73
+ @array << child
74
+ self
75
+ end
76
+
77
+ def accept(visitor)
78
+ visitor.visit_array(self)
79
+ end
80
+ end
81
+
82
+ # define Visitor default actions
83
+ class Visitor
84
+ def visit_node(n); end
85
+
86
+ def visit_array(n)
87
+ for n in n.array do
88
+ n.accept(self)
89
+ end
90
+ end
91
+
92
+ def visit_string(n); end
93
+ def visit_wikiname(n); end
94
+ def visit_url(n); end
95
+ def visit_macro(n); end
96
+ end
97
+
98
+ # visitor for debug
99
+ class DebugVisitor < Visitor
100
+ attr_reader :array
101
+
102
+ def initialize
103
+ @array = []
104
+ end
105
+
106
+ def visit_string(n)
107
+ @array << n.str
108
+ end
109
+
110
+ def visit_wikiname(n)
111
+ @array << sprintf("W:%s", n.str)
112
+ end
113
+
114
+ def visit_url(n)
115
+ @array << sprintf("U:%s", n.str)
116
+ end
117
+
118
+ def visit_macro(n)
119
+ @array << sprintf("M:%s:%s", n.name, n.rest)
120
+ end
121
+ end
122
+ end
123
+
124
+ ---- inner
125
+ # parse one line and return absyn tree for the line
126
+ def parse(line, wikinames)
127
+ @remain = line
128
+ @wikinames = wikinames
129
+ yyparse self, :scan
130
+ @root
131
+ end
132
+
133
+ private
134
+ # Wikiname scanning algorithm is as follows:
135
+ #
136
+ # 1. input: [..............................................................]
137
+ # 2. scan longest wikiname in wikiname-dictionary:
138
+ # [<---heading_remain---->LONGEST_WIKINAME<---trailing_remain--->]
139
+ # 3. for remaining in head & trail, do 2. above recursively
140
+ def scan(&block)
141
+ scan_r(@remain, &block)
142
+ yield [false, nil]
143
+ end
144
+
145
+ URL = '(https?|mailto|ftp):[\w\.\?&/@%^=~#-]+'
146
+
147
+ # recursive scan
148
+ def scan_r(str, &block)
149
+ for w in @wikinames do
150
+ case str
151
+ # to escape wikiname string in <a>...</a>, it is prior to wikiname
152
+ #
153
+ # If word in <a ...>word</a> tag is a wikiname, it would be produced to
154
+ # <a ...><a ...>word</a></a> because it is a wikiname. In order to
155
+ # avoid this, two ways can be considered:
156
+ #
157
+ # 1. introduce escape notation. e.g. rdoc \word
158
+ # 2. introduce special inline escape logic just for <a>...</a>
159
+ #
160
+ # I choose latter for simple usage.
161
+ when /\A([^<]*)(<a[^>]*>[^<]*<\/a>)(.*)\z/m
162
+ scan_r($1, &block)
163
+ yield [:STRING, $2] # <a>...</a> is just string even wikiname be there
164
+ scan_r($3, &block)
165
+ return
166
+
167
+ # to escape wikiname string in HTML tag, it is prior to wikiname
168
+ when /\A([^<]*)(<[^>]*>)(.*)\z/m
169
+ scan_r($1, &block)
170
+ yield [:STRING, $2] # <a>...</a> is just string even wikiname be there
171
+ scan_r($3, &block)
172
+ return
173
+
174
+ # escape of escape: \\{ -> \{
175
+ when /\A([^\\]*)\\\\\{(.*)\z/m
176
+ scan_r($1, &block)
177
+ yield [:STRING, '\\{']
178
+ scan_r($2, &block)
179
+ return
180
+
181
+ # explicit escape by \{!...}
182
+ when /\A([^\\]*)\\\{!([^}]+)\}(.*)\z/m
183
+ scan_r($1, &block)
184
+ yield [:STRING, $2]
185
+ scan_r($3, &block)
186
+ return
187
+
188
+ # macro \{command rest}
189
+ when /\A([^\\]*)\\\{(\w+)\s*([^}]*)\}(.*)\z/m
190
+ scan_r($1, &block)
191
+ yield [:MACRO, [$2, $3]]
192
+ scan_r($4, &block)
193
+ return
194
+
195
+ # URL is piror to wikiname
196
+ when /\A(|.*[^\w])(#{URL})(.*)\z/m
197
+ scan_r($1, &block)
198
+ yield [:URL, $2]
199
+ scan_r($4, &block) # not $3 since URL itself has (...)
200
+ return
201
+
202
+ when /\A(.*)#{w}(.*)\z/m
203
+ scan_r($1, &block)
204
+ yield [:WIKINAME, w]
205
+ scan_r($2, &block)
206
+ return
207
+ end
208
+ end
209
+ yield [:STRING, str]
210
+ end
211
+
212
+ ---- footer
data/lib/juli/macro.rb ADDED
@@ -0,0 +1,39 @@
1
+ module Juli
2
+ module Macro
3
+ class Base
4
+ include Juli::Util
5
+
6
+ # called on 'juli init' to generate config sample template.
7
+ def self.conf_template
8
+ ''
9
+ end
10
+
11
+ # called when juli(1) starts.
12
+ def initialize
13
+ end
14
+
15
+ # called on setting up conf to set default key=val
16
+ def set_conf_default(conf)
17
+ end
18
+
19
+ # called on each parsed document
20
+ def on_root(file, root, visitor = nil)
21
+ end
22
+
23
+ # called on each macro as "\{macro_name args...}" in text.
24
+ # String should be returned.
25
+ def run(*args)
26
+ ''
27
+ end
28
+
29
+ # called at final on each parsed document
30
+ def after_root(file, root)
31
+ end
32
+
33
+ end
34
+
35
+ Dir.glob(File.join(File.dirname(__FILE__), 'macro/*.rb')){|m|
36
+ require File.join('juli/macro', File.basename(m))
37
+ }
38
+ end
39
+ end