juli 2.0.0
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.
- 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
|