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,33 @@
|
|
1
|
+
require 'juli/macro/template_base'
|
2
|
+
|
3
|
+
module Juli
|
4
|
+
module Macro
|
5
|
+
# generate Amazon link
|
6
|
+
#
|
7
|
+
# Amazon link template can be defined at 'amazon' entry in
|
8
|
+
# JULI_REPO/.juli/config.
|
9
|
+
#
|
10
|
+
# if it is not defined, then default template here is used.
|
11
|
+
class Amazon < TemplateBase
|
12
|
+
DEFAULT_TEMPLATE = <<-EOS
|
13
|
+
<iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=wells00-22&o=9&p=8&l=as1&asins=%{asins}&ref=tf_til&fc1=000000&IS2=1<1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr"
|
14
|
+
style="float:right; width:120px;height:240px;"
|
15
|
+
scrolling="no" marginwidth="0" marginheight="0" frameborder="0"
|
16
|
+
></iframe>
|
17
|
+
EOS
|
18
|
+
|
19
|
+
def self.conf_template
|
20
|
+
<<EOM
|
21
|
+
# Amazon association link with any ASIN can be rendered
|
22
|
+
# at any location in juli text. Its template is as follows.
|
23
|
+
# This HTML is just an example so that you can change as you like.
|
24
|
+
# '%{asins}' in the template will be replaced by actual ASIN:
|
25
|
+
#
|
26
|
+
#amazon: '<iframe src="http://rcm-jp.amazon.co.jp/e/cm?o=9&p=8&l=as1&asins=%{asins}&ref=tf_til&fc1=000000&IS2=1<1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr" style="float:right; width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>'
|
27
|
+
EOM
|
28
|
+
end
|
29
|
+
|
30
|
+
def place_holder; 'asins'; end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
require 'juli/macro/template_base'
|
3
|
+
|
4
|
+
module Juli
|
5
|
+
module Macro
|
6
|
+
# generate Map HTML.
|
7
|
+
#
|
8
|
+
# The purpose of this macro is to provide I/F for map.
|
9
|
+
# When map-site(like google) service is discontinued, or
|
10
|
+
# URL is changed, it is enough to change:
|
11
|
+
#
|
12
|
+
# 1. .juli/config jmap entry or
|
13
|
+
# 1. this macro implementation.
|
14
|
+
#
|
15
|
+
# There is no need to modify all of wiki pages which use 'jmap' macro.
|
16
|
+
#
|
17
|
+
# 'J' of jmap stands for Juli. it is because 'map' in ruby is quite common
|
18
|
+
# method so that necessary to avoid name confusion.
|
19
|
+
#
|
20
|
+
# Currently, Google map is used.
|
21
|
+
class Jmap < TemplateBase
|
22
|
+
# Thank you, http://mapki.com/wiki/Google_Map_Parameters !!
|
23
|
+
DEFAULT_TEMPLATE = '<iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="http://maps.google.com/maps?q=loc:%{coord}&num=1&ie=UTF8&t=m&z=14&output=embed"></iframe><br /><small><a href="http://maps.google.com/maps?q=loc:%{coord}&num=1&ie=UTF8&t=m&z=14&source=embed" style="color:#0000FF;text-align:left">View Larger Map</a></small>'
|
24
|
+
|
25
|
+
def self.conf_template
|
26
|
+
<<EOM
|
27
|
+
# HTML template to draw map. If not set, default defined at
|
28
|
+
# Juli::Macro::Jmap::DEFAULT_TEMPLATE is used.
|
29
|
+
# %{coord} in the template wiil be replaced to the actual 1st parameter.
|
30
|
+
#
|
31
|
+
#jmap: '#{DEFAULT_TEMPLATE}'
|
32
|
+
EOM
|
33
|
+
end
|
34
|
+
|
35
|
+
def place_holder; 'coord'; end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'digest/sha1'
|
3
|
+
require 'RMagick'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
module Juli
|
7
|
+
module Macro
|
8
|
+
# embed photo(image) in juli wiki text with minimum maintenance cost
|
9
|
+
#
|
10
|
+
# See 'doc/photo(macro).txt' for the detail.
|
11
|
+
class Photo < Base
|
12
|
+
include Juli::Visitor::Html::TagHelper
|
13
|
+
|
14
|
+
PUBLIC_PHOTO_DIR_DEFAULT = 'public_photo'
|
15
|
+
SEED_DEFAULT = '-- Juli seed default!! --'
|
16
|
+
CONF_DEFAULT = {
|
17
|
+
'mount' => '/home/YOUR_NAME/Photos',
|
18
|
+
'small' => {
|
19
|
+
'width' => 512, # default small width in pixel
|
20
|
+
'style' => 'float: right'
|
21
|
+
},
|
22
|
+
'large' => {
|
23
|
+
'width' => 1024 # default large width in pixel
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
class DirNameConflict < Juli::JuliError; end
|
28
|
+
class ConfigNoMount < Juli::JuliError; end
|
29
|
+
|
30
|
+
def self.conf_template
|
31
|
+
<<EOM
|
32
|
+
# Photo macro setup sample is as follows.
|
33
|
+
#
|
34
|
+
#photo:
|
35
|
+
# mount: '#{CONF_DEFAULT['mount']}'
|
36
|
+
# small:
|
37
|
+
# width: #{CONF_DEFAULT['small']['width']}
|
38
|
+
# style: '#{CONF_DEFAULT['small']['style']}'
|
39
|
+
# large:
|
40
|
+
# width: #{CONF_DEFAULT['large']['width']}
|
41
|
+
EOM
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_conf_default(conf)
|
45
|
+
set_conf_default_sub(conf, 'photo', CONF_DEFAULT)
|
46
|
+
end
|
47
|
+
|
48
|
+
# rotate image to fit orientation
|
49
|
+
def rotate(img)
|
50
|
+
exif = img.get_exif_by_entry(:Orientation)
|
51
|
+
return img if !(exif && exif[0] && exif[0][0] == :Orientation)
|
52
|
+
case exif[0][1]
|
53
|
+
when '1' # Normal
|
54
|
+
img
|
55
|
+
when '6' # 90 degree
|
56
|
+
img.rotate(90) # 90[deg] to clock direction
|
57
|
+
when '8' # 270 degree
|
58
|
+
img.rotate(-90) # 90[deg] to reversed-clock direction
|
59
|
+
else
|
60
|
+
img
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# public photo directory is used to:
|
65
|
+
#
|
66
|
+
# * store converted photo from original one
|
67
|
+
# * protect private photo in 'mount' directory from public web access
|
68
|
+
# by copying (with conversion) to it on demand.
|
69
|
+
#
|
70
|
+
# === INPUTS
|
71
|
+
# url:: when true, return url, else, return physical file-system path
|
72
|
+
def public_photo_dir(url = true)
|
73
|
+
dir = File.join(conf['output_top'], PUBLIC_PHOTO_DIR_DEFAULT)
|
74
|
+
raise DirNameConflict if File.file?(dir)
|
75
|
+
|
76
|
+
if !File.directory?(dir)
|
77
|
+
FileUtils.mkdir(dir)
|
78
|
+
end
|
79
|
+
url ? PUBLIC_PHOTO_DIR_DEFAULT : dir
|
80
|
+
end
|
81
|
+
|
82
|
+
# simplify path to the non-directory name with size.
|
83
|
+
#
|
84
|
+
# === Example
|
85
|
+
# path:: a/b/c.jpg
|
86
|
+
# photo_name:: a_b_c_#{size}.jpg
|
87
|
+
def photo_name(path, size)
|
88
|
+
flat = path.gsub(/\//, '_')
|
89
|
+
sprintf("%s_%s%s",
|
90
|
+
File.basename(flat, '.*'), size, File.extname(flat))
|
91
|
+
end
|
92
|
+
|
93
|
+
# cached photo path
|
94
|
+
#
|
95
|
+
# === INPUTS
|
96
|
+
# path:: photo-macro path argument
|
97
|
+
# size:: :small, or :large
|
98
|
+
# url:: when true, return url, else, return physical file-system path
|
99
|
+
def photo_path(path, size, url = true)
|
100
|
+
File.join(public_photo_dir(url), photo_name(path, size))
|
101
|
+
end
|
102
|
+
|
103
|
+
# create resized, rotated, and 'exif' eliminated cache when:
|
104
|
+
# 1. not already created, or
|
105
|
+
# 1. cache is obsolete
|
106
|
+
#
|
107
|
+
# and return the path.
|
108
|
+
#
|
109
|
+
# === INPUTS
|
110
|
+
# path:: photo-macro path argument
|
111
|
+
# size:: :small, or :large
|
112
|
+
# url:: when true, return url, else, return physical file-system path
|
113
|
+
def intern(path, size = :small, url = true)
|
114
|
+
protected_path = File.join(conf_photo['mount'], path)
|
115
|
+
public_phys_path = photo_path(path, size, false)
|
116
|
+
if !File.exist?(public_phys_path) ||
|
117
|
+
File::Stat.new(public_phys_path).mtime < File::Stat.new(protected_path).mtime
|
118
|
+
|
119
|
+
img = Magick::ImageList.new(protected_path)
|
120
|
+
width = (s = conf_photo[size.to_s]) && s['width']
|
121
|
+
img.resize_to_fit!(width, img.rows * width / img.columns)
|
122
|
+
self.rotate(img).
|
123
|
+
strip!.
|
124
|
+
write(public_phys_path).destroy!
|
125
|
+
end
|
126
|
+
photo_path(path, size, url)
|
127
|
+
end
|
128
|
+
|
129
|
+
# return <img...> HTML tag for the photo with this macro features.
|
130
|
+
def run(*args)
|
131
|
+
path = args[0].gsub(/\.\./, '') # sanitize '..'
|
132
|
+
style = conf_photo['small']['style']
|
133
|
+
small_url = intern(path)
|
134
|
+
large_url = intern(path, :large)
|
135
|
+
content_tag(:a, :href=>large_url) do
|
136
|
+
tag(:img,
|
137
|
+
:src => intern(path),
|
138
|
+
:class => 'juli_photo_small',
|
139
|
+
:style => style)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def conf_photo
|
144
|
+
@conf_photo ||= conf['photo']
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
def set_conf_default_sub(hash, key, val)
|
149
|
+
case val
|
150
|
+
when Hash
|
151
|
+
hash[key] = {} if !hash[key]
|
152
|
+
for k, v in val do
|
153
|
+
set_conf_default_sub(hash[key], k, v)
|
154
|
+
end
|
155
|
+
else
|
156
|
+
hash[key] = val if !hash[key]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
require 'sdbm'
|
4
|
+
|
5
|
+
module Juli
|
6
|
+
module Macro
|
7
|
+
# Register tags of this document for tag-search.
|
8
|
+
#
|
9
|
+
# See 'doc/tag(macro).txt' for the detail how to use it.
|
10
|
+
# Here is the implementation document.
|
11
|
+
#
|
12
|
+
# === Tag-DB ER-chart
|
13
|
+
# tag <--->> tag_page <<---> page
|
14
|
+
#
|
15
|
+
# * tag DB value counts number of wikipages
|
16
|
+
#
|
17
|
+
# === FILES
|
18
|
+
# JURI_REPO/.juli/tag.sdbm:: tag DB
|
19
|
+
# JURI_REPO/.juli/page.sdbm:: page DB
|
20
|
+
# JURI_REPO/.juli/tag_page.sdbm:: tag-page intersection DB
|
21
|
+
class Tag < Base
|
22
|
+
SEPARATOR = '_, _'
|
23
|
+
NO_TAG = '_no_tag_'
|
24
|
+
|
25
|
+
attr_accessor :tag_db, :page_db, :tag_page_db
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
super
|
29
|
+
|
30
|
+
repo_dir = File.join(juli_repo, Juli::REPO)
|
31
|
+
@tag_db = SDBM.open(File.join(repo_dir, 'tag.sdbm'))
|
32
|
+
@page_db = SDBM.open(File.join(repo_dir, 'page.sdbm'))
|
33
|
+
@tag_page_db = SDBM.open(File.join(repo_dir, 'tag_page.sdbm'))
|
34
|
+
end
|
35
|
+
|
36
|
+
# register page
|
37
|
+
def on_root(file, root, visitor = nil)
|
38
|
+
@wikiname = Juli::Util::to_wikiname(file)
|
39
|
+
@page_db[@wikiname] = '1'
|
40
|
+
@tag_exists = false
|
41
|
+
end
|
42
|
+
|
43
|
+
def run(*args)
|
44
|
+
for tag in args do
|
45
|
+
@tag_exists = true
|
46
|
+
|
47
|
+
# +1 on tag
|
48
|
+
@tag_db[tag] = ((@tag_db[tag] || '0').to_i + 1).to_s
|
49
|
+
if @wikiname
|
50
|
+
@tag_page_db[tag_page_key(tag, @wikiname)] = '1'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
''
|
54
|
+
end
|
55
|
+
|
56
|
+
# follow-up process to register 'no-tag' if there is no tag in the
|
57
|
+
# file.
|
58
|
+
def after_root(file, root)
|
59
|
+
key = sprintf("%s%s%s", @wikiname, SEPARATOR, NO_TAG)
|
60
|
+
if @tag_exists
|
61
|
+
@tag_page_db.delete(key)
|
62
|
+
else
|
63
|
+
@tag_page_db[key] = '1'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# value in sdbm in ruby 1.9 looks not to support encoding
|
68
|
+
# (in other words, always set to ASCII-8BIT) so that
|
69
|
+
# enforce to set it to UTF-8.
|
70
|
+
def to_utf8(v)
|
71
|
+
v.force_encoding(Encoding::UTF_8)
|
72
|
+
end
|
73
|
+
|
74
|
+
# return pages associated with key
|
75
|
+
def pages(key)
|
76
|
+
result = []
|
77
|
+
for tag_page, val in @tag_page_db do
|
78
|
+
if to_utf8(tag_page) =~ /^(.*)#{SEPARATOR}#{key}$/
|
79
|
+
result << $1
|
80
|
+
end
|
81
|
+
end
|
82
|
+
result
|
83
|
+
end
|
84
|
+
|
85
|
+
def max_tag_weight
|
86
|
+
@tag_db.values.map{|v| v.to_i}.max || 1
|
87
|
+
end
|
88
|
+
|
89
|
+
# return 0..10 in tag weight v.s. max-weight
|
90
|
+
def tag_weight_ratio(key)
|
91
|
+
v = (@tag_db[key] || '0').to_i
|
92
|
+
(v * 10 / max_tag_weight).to_i
|
93
|
+
end
|
94
|
+
|
95
|
+
# delete entry from DB
|
96
|
+
def delete_page(file)
|
97
|
+
wikiname = Juli::Util::to_wikiname(file)
|
98
|
+
@page_db.delete(wikiname)
|
99
|
+
|
100
|
+
tag_on_the_file = {}
|
101
|
+
for tag, val in @tag_db.keys do
|
102
|
+
if @tag_page_db[tag_page_key(tag, wikiname)]
|
103
|
+
tag_on_the_file[tag] = 1
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# -1 on tag
|
108
|
+
for tag in tag_on_the_file.keys do
|
109
|
+
@tag_db[tag] = ((@tag_db[tag] || '1').to_i - 1).to_s
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# print DB info; debugging purpose. How to use:
|
114
|
+
#
|
115
|
+
# $ test/console
|
116
|
+
# > Dir.chdir('../test/repo')
|
117
|
+
# > include Juli::Util
|
118
|
+
# > t = Juli::Macro::Tag.new
|
119
|
+
# > t.dump
|
120
|
+
def dump
|
121
|
+
for db in %w(tag_db page_db tag_page_db) do
|
122
|
+
printf("%s\n", db)
|
123
|
+
for key, val in instance_variable_get('@' + db) do
|
124
|
+
printf(" %s\t%s\n", key, val)
|
125
|
+
end
|
126
|
+
print "\n"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
def tag_page_key(tag, wikiname)
|
132
|
+
sprintf("%s%s%s", wikiname, SEPARATOR, tag)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
require 'sdbm'
|
4
|
+
|
5
|
+
module Juli
|
6
|
+
module Macro
|
7
|
+
# set ERB template.
|
8
|
+
#
|
9
|
+
# ERB template, which is used on generating HTML from juli-formatted text,
|
10
|
+
# can be specified by:
|
11
|
+
#
|
12
|
+
# 1. juli(1) command line -t option.
|
13
|
+
# 1. this macro
|
14
|
+
# 1. .juli/config template directive.
|
15
|
+
# 1. lib/juli/template
|
16
|
+
#
|
17
|
+
# See 'doc/template(macro).txt' for the detail how to use it.
|
18
|
+
# Here is the implementation document.
|
19
|
+
#
|
20
|
+
# NOTE: Template class is <b>totally different</b> from TemplateBase.
|
21
|
+
# Template is to specify ERB template, while TemplateBase is the
|
22
|
+
# base class to provide HTML flagment replacement in a juli document.
|
23
|
+
class Template < Base
|
24
|
+
# save visitor for later use at run()
|
25
|
+
def on_root(file, root, visitor = nil)
|
26
|
+
@visitor = visitor
|
27
|
+
end
|
28
|
+
|
29
|
+
def run(*args)
|
30
|
+
if @visitor.respond_to?('template=')
|
31
|
+
@visitor.template = args[0]
|
32
|
+
end
|
33
|
+
''
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Juli
|
2
|
+
module Macro
|
3
|
+
# Base class for HTML template related macros.
|
4
|
+
#
|
5
|
+
# Derived class can provide HTML template replacement with minimum
|
6
|
+
# implementation. Please see Wikipedia case as an example.
|
7
|
+
class TemplateBase < Base
|
8
|
+
DEFAULT_TEMPLATE = ''
|
9
|
+
|
10
|
+
def self.conf_template
|
11
|
+
''
|
12
|
+
end
|
13
|
+
|
14
|
+
# return key string used for conf-key
|
15
|
+
#
|
16
|
+
# Please overwrite this method if it is not just underscore-ed.
|
17
|
+
def conf_key
|
18
|
+
Juli::Util::underscore(self.class.to_s)
|
19
|
+
end
|
20
|
+
|
21
|
+
# set default value in conf if no .juli/conf defined.
|
22
|
+
#
|
23
|
+
# Please overwrite this method when this implementation is not your
|
24
|
+
# case.
|
25
|
+
def set_conf_default(conf)
|
26
|
+
if !conf[conf_key]
|
27
|
+
conf[conf_key] = self.class::DEFAULT_TEMPLATE
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# return string used to be replaced with %{...} in conf[conf_key] string.
|
32
|
+
#
|
33
|
+
# Please overwrite this method if it is not just underscore-ed.
|
34
|
+
def place_holder
|
35
|
+
conf_key
|
36
|
+
end
|
37
|
+
|
38
|
+
def run(*args)
|
39
|
+
template = conf[conf_key]
|
40
|
+
template.gsub("%{#{place_holder}}", args[0])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|