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