juli 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +26 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.rdoc +39 -0
- data/Rakefile +89 -0
- data/bin/console +14 -0
- data/bin/je +73 -0
- data/bin/juli +82 -0
- data/bin/juli_tb.rb +76 -0
- data/bin/setup +7 -0
- data/juli.gemspec +29 -0
- data/lib/juli.rb +21 -0
- data/lib/juli/absyn.rb +206 -0
- data/lib/juli/command.rb +180 -0
- data/lib/juli/command/file_entry.rb +12 -0
- data/lib/juli/command/recent_update.rb +52 -0
- data/lib/juli/command/sitemap.rb +55 -0
- data/lib/juli/command/tag.rb +81 -0
- data/lib/juli/line_parser.y +212 -0
- data/lib/juli/macro.rb +39 -0
- data/lib/juli/macro/amazon.rb +33 -0
- data/lib/juli/macro/jmap.rb +38 -0
- data/lib/juli/macro/photo.rb +161 -0
- data/lib/juli/macro/tag.rb +136 -0
- data/lib/juli/macro/template.rb +37 -0
- data/lib/juli/macro/template_base.rb +44 -0
- data/lib/juli/macro/wikipedia.rb +19 -0
- data/lib/juli/parser.y +360 -0
- data/lib/juli/template/default.html +64 -0
- data/lib/juli/template/facebook.html +82 -0
- data/lib/juli/template/je-bash-complete +42 -0
- data/lib/juli/template/juli.css +173 -0
- data/lib/juli/template/juli.js +87 -0
- data/lib/juli/template/locale/en.yml +10 -0
- data/lib/juli/template/locale/ja.yml +10 -0
- data/lib/juli/template/prototype.js +4320 -0
- data/lib/juli/template/simple.html +45 -0
- data/lib/juli/template/sitemap.html +78 -0
- data/lib/juli/template/sitemap_order_by_mtime_DESC.html +78 -0
- data/lib/juli/template/slidy.html +126 -0
- data/lib/juli/template/sourceforge.html +71 -0
- data/lib/juli/template/takahashi_method.html +116 -0
- data/lib/juli/util.rb +255 -0
- data/lib/juli/util/juli_i18n.rb +32 -0
- data/lib/juli/version.rb +3 -0
- data/lib/juli/visitor.rb +12 -0
- data/lib/juli/visitor/html.rb +462 -0
- data/lib/juli/visitor/html/helper.rb +97 -0
- data/lib/juli/visitor/html/helper/contents.rb +76 -0
- data/lib/juli/visitor/html/helper/fb_comments.rb +68 -0
- data/lib/juli/visitor/html/helper/fb_like.rb +37 -0
- data/lib/juli/visitor/html/tag_helper.rb +40 -0
- data/lib/juli/visitor/slidy.rb +39 -0
- data/lib/juli/visitor/takahashi_method.rb +41 -0
- data/lib/juli/visitor/tree.rb +135 -0
- data/lib/juli/wiki.rb +52 -0
- data/sample/protected_photo/2012-04-22/DCIM/101_PANA/P1010441.JPG +0 -0
- data/sample/update_public_juli.rb +71 -0
- data/setup.rb +1585 -0
- metadata +211 -0
@@ -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
|