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,97 @@
1
+ require 'i18n'
2
+
3
+ class Juli::Visitor::Html
4
+ # This provides methods used in HTML Erb; called 'helper'.
5
+ #
6
+ # Any method here can be used at ERB template under LIB/juli/template/.
7
+ # Where, LIB is 'lib/' directory in package environment, or
8
+ # one of $LOAD_PATH in installed environment.
9
+ #
10
+ # === How to add new helper(1)
11
+ # If new method is added in this module, it can be used as helper at
12
+ # template ERB file. This is the simplest case.
13
+ #
14
+ # === How to add new helper(2)
15
+ # If some preparation is required before calling helper, above way is not
16
+ # enough. For example, recent_update() helper requires file list
17
+ # which is sorted by descendant order of mtime timestamp.
18
+ # It is time-consuming task to prepare such a file list on every
19
+ # recent_update() calling. It is enough to do that only once when juli(1)
20
+ # is executed.
21
+ #
22
+ # Another example: if the same helper is called more than once in one
23
+ # template, it could be effective to reduce the CPU resource to
24
+ # prepare some data and store it in the helper class instance then
25
+ # each helper uses it just to print the result.
26
+ #
27
+ # Juli supports such a case. Let me assume here to write
28
+ # 'weather_forecast' helper, which draws some local area's
29
+ # one week weather forecast (juli(1) is offline wiki so that
30
+ # this kind of realtime information is not a good example though...).
31
+ # Follow the steps below:
32
+ # 1. Write WeatherForecast helper class file as
33
+ # LIB/juli/visitor/html/helper/weather_forecast.rb.
34
+ # (recent_update.rb could be a reference for this.)
35
+ # 1. WeatherForecast should inherit
36
+ # Juli::Visitor::Html::Helper::AbstractHelper.
37
+ # 1. implement each method: initialize, on_root, run.
38
+ #
39
+ # Then, weather_forecast method can be used in ERB template.
40
+ # This method is dynamically defined at Html visitor and equivalent
41
+ # to WeatherForecast#run.
42
+ #
43
+ module Helper
44
+ class AbstractHelper
45
+ include Juli::Util
46
+
47
+ # called on 'juli init' to generate config sample template.
48
+ def self.conf_template
49
+ ''
50
+ end
51
+
52
+ # called when juli(1) starts.
53
+ def initialize
54
+ end
55
+
56
+ # called on setting up conf to set default key=val
57
+ def set_conf_default(conf)
58
+ end
59
+
60
+ # called on each parsed document
61
+ def on_root(in_file, root, visitor)
62
+ end
63
+
64
+ # This will be a helper like 'abstract_helper(args)'
65
+ def run(*args)
66
+ end
67
+ end
68
+
69
+ # TRICKY PART: header_id is used for 'contents' helper link.
70
+ # Absyn::HeaderNode.dom_id cannot be used directory for
71
+ # this purpose since when clicking a header of 'contents',
72
+ # document jumps to its contents rather than header so that
73
+ # header is hidden on browser. To resolve this, header_id
74
+ # is required for 'contents' helper and it is set at Html visitor.
75
+ def header_id(n)
76
+ "#{n.dom_id}_header"
77
+ end
78
+
79
+ # dest's relative path from src
80
+ #
81
+ # === EXAMPLE
82
+ # relative_from('a.txt', 'juli.js'):: → './juli.js'
83
+ # relative_from('a/b.txt', 'juli.js'):: → '../juli.js'
84
+ def relative_from(src, dest)
85
+ result = []
86
+ Pathname.new(File.dirname(src)).descend{|dir|
87
+ result << (dir.to_s == '.' ? '.' : '..')
88
+ }
89
+ File.join(result, dest)
90
+ end
91
+
92
+ # import all of helper/*.rb files
93
+ Dir.glob(File.join(File.dirname(__FILE__), 'helper/*.rb')){|v|
94
+ require File.join('juli/visitor/html/helper', File.basename(v))
95
+ }
96
+ end
97
+ end
@@ -0,0 +1,76 @@
1
+ module Juli::Visitor::Html::Helper
2
+ # Helper-class for 'contents' helper
3
+ class Contents < AbstractHelper
4
+ # Check if chapter exists or not
5
+ class ChapterChecker < Juli::Absyn::Visitor
6
+ attr_accessor :chapter_exists
7
+
8
+ def initialize(opts = {})
9
+ @chapter_exists = false
10
+ super
11
+ end
12
+
13
+ def visit_chapter(n)
14
+ @chapter_exists = true
15
+ end
16
+ end
17
+
18
+ class ContentsDrawer < Juli::Absyn::Visitor
19
+ include Juli::Visitor::Html::TagHelper
20
+ include Juli::Visitor::Html::Helper
21
+
22
+ def visit_node(n); ''; end
23
+ def visit_str(n); ''; end
24
+ def visit_verbatim(n); ''; end
25
+ def visit_ordered_list(n); ''; end
26
+ def visit_unordered_list(n); ''; end
27
+ def visit_compact_dictionary_list(n); ''; end
28
+ def visit_compact_dictionary_list_item(n); ''; end
29
+ def visit_dictionary_list(n); ''; end
30
+ def visit_dictionary_list_item(n); ''; end
31
+
32
+ def visit_array(n)
33
+ n.array.inject(''){|result, child|
34
+ result += child.accept(self)
35
+ }
36
+ end
37
+
38
+ def visit_chapter(n)
39
+ content_tag(:li) do
40
+ content_tag(:a, :href=>'#' + header_id(n)) do
41
+ n.str
42
+ end +
43
+ content_tag(:ol) do
44
+ n.blocks.accept(self)
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ # called on each parsed document
51
+ def on_root(in_file, root, visitor = nil)
52
+ @root = root
53
+ end
54
+
55
+ # implementation of:
56
+ # contents
57
+ #
58
+ # which draws contents(a.k.a. outline) of this document.
59
+ #
60
+ # This visits document tree by ContentsDrawer visitor and
61
+ # generate HTML contents list.
62
+ def run(*args)
63
+ contents_drawer = ContentsDrawer.new
64
+ chapter_checker = ChapterChecker.new
65
+ @root.accept(chapter_checker)
66
+ if chapter_checker.chapter_exists
67
+ contents_drawer.content_tag(:b, I18n.t('contents')) +
68
+ contents_drawer.content_tag(:ol) do
69
+ @root.accept(contents_drawer)
70
+ end
71
+ else
72
+ ''
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,68 @@
1
+ module Juli::Visitor::Html::Helper
2
+ # Helper-class for 'fb_like' helper
3
+ class FbComments < AbstractHelper
4
+ # default HTML template for facebook 'like' button.
5
+ # You can customize it in .juli/config facebook.like.template entry.
6
+ #
7
+ # %{href} in the template will be replaced to the actual URL of
8
+ # current wiki page.
9
+ DEFAULT_TEMPLATE =
10
+ '<fb:comments href="%{href}" num_posts="2" width="470">' +
11
+ '</fb:comments>'
12
+
13
+ # called on 'juli init' to generate config sample template.
14
+ def self.conf_template
15
+ <<EOM
16
+ # Facebook related setup is here.
17
+ #
18
+ #url_prefix: 'http://YOUR_HOST/juli'
19
+ #facebook:
20
+ # like:
21
+ # template: '#{Juli::Visitor::Html::Helper::FbLike::DEFAULT_TEMPLATE}'
22
+ # comments:
23
+ # template: '#{DEFAULT_TEMPLATE}'
24
+ EOM
25
+ end
26
+
27
+ def initialize
28
+ @fb_conf = conf['facebook']
29
+ end
30
+
31
+ # set default value in conf if no .juli/conf defined.
32
+ #
33
+ # Please overwrite this method when this implementation is not your
34
+ # case.
35
+ def set_conf_default(conf)
36
+ conf['url_prefix'] = 'http://YOUR_HOST/juli' if !conf['url_prefix']
37
+ conf['facebook'] = {} if !conf['facebook']
38
+ if !conf['facebook']['comments']
39
+ conf['facebook']['comments'] = {
40
+ 'template' => self.class::DEFAULT_TEMPLATE
41
+ }
42
+ end
43
+ if !conf['facebook']['like']
44
+ conf['facebook']['like'] = {
45
+ 'template' => Juli::Visitor::Html::Helper::FbLike::DEFAULT_TEMPLATE
46
+ }
47
+ end
48
+ end
49
+
50
+ # called on each parsed document
51
+ def on_root(in_file, root, visitor = nil)
52
+ @in_file = in_file
53
+ end
54
+
55
+ def run(*args)
56
+ raise Juli::NoConfig if !conf['url_prefix']
57
+ raise Juli::NoConfig if !@in_file
58
+
59
+ template.gsub('%{href}',
60
+ conf['url_prefix'] + '/' + to_wikiname(@in_file) + conf['ext'])
61
+ end
62
+
63
+ private
64
+ def template
65
+ @fb_conf['comments']['template']
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,37 @@
1
+ module Juli::Visitor::Html::Helper
2
+ # Helper-class for 'fb_like' helper
3
+ class FbLike < AbstractHelper
4
+ # default HTML template for facebook 'like' button.
5
+ # You can customize it in .juli/config facebook.like.template entry.
6
+ #
7
+ # %{href} in the template will be replaced to the actual URL of
8
+ # current wiki page.
9
+ DEFAULT_TEMPLATE =
10
+ '<fb:like href="%{href}" ' +
11
+ 'send="false" layout="button_count" width="450" ' +
12
+ 'show_faces="false">' +
13
+ '</fb:like>'
14
+
15
+ def initialize
16
+ @fb_conf = conf['facebook']
17
+ end
18
+
19
+ # called on each parsed document
20
+ def on_root(in_file, root, visitor = nil)
21
+ @in_file = in_file
22
+ end
23
+
24
+ def run(*args)
25
+ raise Juli::NoConfig if !conf['url_prefix']
26
+ raise Juli::NoConfig if !@in_file
27
+
28
+ template.gsub('%{href}',
29
+ conf['url_prefix'] + '/' + to_wikiname(@in_file) + conf['ext'])
30
+ end
31
+
32
+ private
33
+ def template
34
+ @fb_conf['like']['template']
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,40 @@
1
+ class Juli::Visitor::Html
2
+ # copied from Rails
3
+ module TagHelper
4
+ def tag(name, options = nil, open = false)
5
+ "<#{name}#{tag_options(options) if options}#{open ? ">" : " />"}"
6
+ end
7
+
8
+ def content_tag(name, content_or_options_with_block = nil, options = nil, &block)
9
+ if block_given?
10
+ options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
11
+ content_tag_string(name, block.call, options)
12
+ else
13
+ content_tag_string(name, content_or_options_with_block, options)
14
+ end
15
+ end
16
+
17
+ private
18
+ BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked)
19
+ BOOLEAN_ATTRIBUTES << BOOLEAN_ATTRIBUTES.map{|s| s.to_sym}
20
+
21
+ def content_tag_string(name, content, options)
22
+ tag_options = tag_options(options) if options
23
+ "<#{name}#{tag_options}>#{content}</#{name}>"
24
+ end
25
+
26
+ def tag_options(options)
27
+ if options != {}
28
+ attrs = []
29
+ options.each_pair do |key, value|
30
+ if BOOLEAN_ATTRIBUTES.include?(key)
31
+ attrs << key if value
32
+ else
33
+ attrs << %(#{key}="#{value}") if !value.nil?
34
+ end
35
+ end
36
+ " #{attrs.sort * ' '}" unless attrs.empty?
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,39 @@
1
+ module Juli::Visitor
2
+ # This visits Absyn tree and generates HTML for Slideshow.
3
+ #
4
+ # Text files under juli-repository must have '.txt' extention.
5
+ #
6
+ # Almost all are the same as Html VISITOR.
7
+ #
8
+ # === OPTIONS
9
+ # -t template:: specify template
10
+ class Slidy < Html
11
+ # bulk-mode for slideshow generation doesn't make sense so that
12
+ # it just warns and return quickly.
13
+ def run_bulk
14
+ STDERR.printf("bulk-mode in Slidy is not supported.\n")
15
+ end
16
+
17
+ # overwrite to:
18
+ # * add 'slide' stylesheet-class at level==1
19
+ # * include all contents in 'slide' stylesheet-class even title
20
+ def visit_chapter(n)
21
+ attr = {:id=>n.dom_id}
22
+ if n.level==1
23
+ attr.merge!(:class=>'slide')
24
+ end
25
+ content_tag(:div, attr) do
26
+ header_link(n) +
27
+ n.blocks.accept(self)
28
+ end + "\n"
29
+ end
30
+
31
+ private
32
+ # overwrite to generate simple <h#>...</h#>
33
+ def header_link(n)
34
+ content_tag("h#{n.level + 1}") do
35
+ @header_sequence.gen(n.level) + '. ' + n.str
36
+ end + "\n"
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,41 @@
1
+ module Juli::Visitor
2
+ # This visits Absyn tree and generates HTML for
3
+ # 'Takahashi method' slideshow.
4
+ #
5
+ # Text files under juli-repository must have '.txt' extention.
6
+ #
7
+ # Almost all are the same as Html VISITOR.
8
+ #
9
+ # === OPTIONS
10
+ # -t template:: specify template
11
+ class TakahashiMethod < Html
12
+ # bulk-mode in TakahashiMethod doesn't make sense so that
13
+ # it just warns and return quickly.
14
+ def run_bulk
15
+ STDERR.printf("bulk-mode in TakahashiMethod is not supported.\n")
16
+ end
17
+
18
+ private
19
+ # overwrite to generate simple <h# class=slide>...</h#>
20
+ def header_link(n)
21
+ content_tag("h#{n.level + 1}", :class=>'slide') do
22
+ @header_sequence.gen(n.level) + '. ' + n.str
23
+ end + "\n"
24
+ end
25
+
26
+ # specify paragraph css
27
+ def paragraph_css
28
+ {:class=>'default slide'}
29
+ end
30
+
31
+ # specify blockquote css
32
+ def blockquote_css
33
+ {:class=>'slide'}
34
+ end
35
+
36
+ # specify list item css
37
+ def list_item_css
38
+ {:class=>'slide'}
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,135 @@
1
+ require 'juli/absyn'
2
+ require 'juli/util'
3
+ require 'juli/line_parser.tab'
4
+
5
+ module Juli::Visitor
6
+ class LineTree < Juli::LineAbsyn::Visitor
7
+ include Juli::Util
8
+
9
+ def initialize(depth)
10
+ @depth = depth
11
+ end
12
+
13
+ def print_depth
14
+ print '| ' * @depth
15
+ end
16
+
17
+ def visit_string(n)
18
+ print_depth
19
+ printf "str: %s\n", str_trim(n.str)
20
+ end
21
+
22
+ def visit_wikiname(n)
23
+ print_depth
24
+ printf "wiki: %s\n", str_trim(n.str)
25
+ end
26
+
27
+ def visit_url(n)
28
+ print_depth
29
+ printf "url: %s\n", str_trim(n.str)
30
+ end
31
+ end
32
+
33
+ # Another VISITOR-pattern for Absyn tree to print tree
34
+ # structure around each node.
35
+ class Tree < Juli::Absyn::Visitor
36
+ include Juli::Util
37
+
38
+ # visit root to generate absyn-tree structure.
39
+ def run_file(in_file, root)
40
+ @depth = 0
41
+ super
42
+ end
43
+
44
+ def visit_str(n)
45
+ print_depth
46
+ printf("StrNode(%d)\n", -1)
47
+ @depth += 1
48
+ process_str(n.str)
49
+ @depth -= 1
50
+ end
51
+
52
+ def visit_verbatim(n)
53
+ print_depth
54
+ printf("verbatim: %s\n", str_trim(n.str))
55
+ end
56
+
57
+ def visit_array(n)
58
+ print_depth
59
+ printf("Array\n")
60
+ @depth += 1
61
+ for child in n.array do
62
+ child.accept(self)
63
+ end
64
+ @depth -= 1
65
+ end
66
+
67
+ def visit_chapter(n)
68
+ print_depth
69
+ printf("Chapter(%d %s)\n", n.level, n.str)
70
+ @depth += 1
71
+ n.blocks.accept(self)
72
+ @depth -= 1
73
+ end
74
+
75
+ def visit_ordered_list(n)
76
+ visit_list("OrderedList\n", n)
77
+ end
78
+
79
+ def visit_unordered_list(n)
80
+ visit_list("UnorderedList\n", n)
81
+ end
82
+
83
+ def visit_compact_dictionary_list(n)
84
+ visit_list("CompactDictionaryList\n", n)
85
+ end
86
+
87
+ def visit_compact_dictionary_list_item(n)
88
+ visit_x_dictionary_list_item(n, "CompactDictionaryListItem\n")
89
+ end
90
+
91
+ def visit_dictionary_list(n)
92
+ visit_list("DictionaryList\n", n)
93
+ end
94
+
95
+ def visit_dictionary_list_item(n)
96
+ visit_x_dictionary_list_item(n, "DictionaryListItem\n")
97
+ end
98
+
99
+ def visit_quote(n)
100
+ print_depth
101
+ printf("QuoteNode(%s)\n", str_trim(n.str))
102
+ end
103
+
104
+ private
105
+ def print_depth
106
+ print '| ' * @depth
107
+ end
108
+
109
+ def visit_list(class_str, n)
110
+ print_depth
111
+ printf(class_str)
112
+ @depth += 1
113
+ for child in n.array do
114
+ child.accept(self)
115
+ end
116
+ @depth -= 1
117
+ end
118
+
119
+ # common for both dictionary list item and compact dictionary list item
120
+ def visit_x_dictionary_list_item(n, node_name)
121
+ print_depth
122
+ printf(node_name)
123
+ @depth += 1
124
+ process_str(n.term)
125
+ process_str(n.str)
126
+ @depth -= 1
127
+ end
128
+
129
+ # str -> Juli::LineAbsyn -> print with depth
130
+ def process_str(str)
131
+ Juli::LineParser.new.parse(str, Juli::Wiki.wikinames).
132
+ accept(LineTree.new(@depth))
133
+ end
134
+ end
135
+ end