honyomi 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 68f371dc5130aa8dc7f02f3464902d28628ba38a
4
- data.tar.gz: dceceb65a54d4944993a91ae8d8a75b7576d9a0e
3
+ metadata.gz: e2f44bb420e77ab9fbef9b1508052aca915ffbd7
4
+ data.tar.gz: d443c1e385c34c9f67f25cffc201070a49503dd2
5
5
  SHA512:
6
- metadata.gz: 7ca2111c247ee0bea1a11e74a3b6d57479e361bd148b76fb8f3873c3e349c079fbf39e3c14ceb6744053b1007b5cb2e6b0e287edbaf2dd7d8a825f2a3bc17ebd
7
- data.tar.gz: c733a8d9b8420a5b92fb0df4b317931a10ac1bd03cf336bf265e4521ab08abbd26ff1d6711a812cefdbf5b4977dd05c7150921cedef13ebe8a51bb7f07fb330e
6
+ metadata.gz: b9dd0c9422a025fefa25e36d64bfd20b5f0083d16595219b920acb6ce67529adda81624cefb6801714f50a51765b999024fd0b77121c1acbd3c6daedd5956c4b
7
+ data.tar.gz: da02decc4acb9741aae5492378f520b3c0940026f2717d3a7b4a3ed6051d84b120470f99a57807211b9446914016cb9e1b443adb3482905995a0ba7662799590
data/HISTORY.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # HISTORY - Honyomi
2
2
 
3
+ ## 1.0 - 2014-11-15
4
+
5
+ * Bookmark a page
6
+ * Click star
7
+ * Is also attached comments
8
+ * Link page no (P111)
9
+ * Auto link http://...
10
+ * Ctrl+Enter: Shortcut to Update
11
+
12
+ * Edit a book information on web
13
+ * Title, Author, URL
14
+
15
+ * Convenient search query
16
+ * `123`: Jump to page
17
+ * `b:11 hello`: Book Id
18
+ * `-b:11 hello`: Book Id (NOT)
19
+ * `t:hello world`: Book Title
20
+ * `p:>100 p:<200 world`: Page Number
21
+
22
+ * Help
23
+
24
+ * Clear Button
25
+
26
+ * Impliment Util.highlight_keywords using Groonga::PatriciaTrie#tag_keys instead of Pure Ruby
27
+
3
28
  ## 0.2 - 2014-10-07
4
29
 
5
30
  * Improve search result
data/lib/honyomi/cli.rb CHANGED
@@ -62,6 +62,8 @@ module Honyomi
62
62
 
63
63
  desc "edit book_id [options]", "Edit book info"
64
64
  option :title, :aliases => '-t', :type => :string, :desc => 'Change title'
65
+ option :author, :aliases => '-a', :type => :string, :desc => 'Change author'
66
+ option :url, :aliases => '-u', :type => :string, :desc => 'Change url'
65
67
  option :path, :type => :string, :desc => 'Change file path'
66
68
  option :strip, :type => :boolean, :desc => 'Remove spaces'
67
69
  option :no_strip, :type => :boolean, :desc => 'Not remove spaces'
@@ -70,9 +72,14 @@ module Honyomi
70
72
  core = Core.new
71
73
  core.load_database
72
74
 
73
- book_id = args[0].to_i
74
- core.edit(book_id, options)
75
- puts core.list([book_id])
75
+ begin
76
+ book_id = args[0].to_i
77
+ core.edit(book_id, options)
78
+ puts core.list([book_id])
79
+ rescue HonyomiError => e
80
+ puts e
81
+ exit -1
82
+ end
76
83
  end
77
84
 
78
85
  desc "remove book_id1 [book_id2 ...]", "Remove books"
@@ -91,8 +98,7 @@ module Honyomi
91
98
  core = Core.new
92
99
  core.load_database
93
100
 
94
- results = core.search(args.join(" "))
95
- snippet = GrnMini::Util.text_snippet_from_selection_results(results)
101
+ results, snippet = core.search(args.join(" "))
96
102
 
97
103
  puts "#{results.size} matches"
98
104
  results.map do |page|
data/lib/honyomi/core.rb CHANGED
@@ -41,6 +41,8 @@ module Honyomi
41
41
  def edit(book_id, options)
42
42
  opts = {}
43
43
  opts[:title] = options[:title] if options[:title]
44
+ opts[:author] = options[:author] if options[:author]
45
+ opts[:url] = options[:url] if options[:url]
44
46
  opts[:path] = options[:path] if options[:path]
45
47
  opts[:timestamp] = Time.parse(options[:timestamp]) if options[:timestamp]
46
48
 
@@ -58,7 +60,7 @@ module Honyomi
58
60
  end
59
61
 
60
62
  def search(query)
61
- @database.search(query)
63
+ @database.search(Query.new(query), cli: true)
62
64
  end
63
65
 
64
66
  def list(args = [], options = {})
@@ -81,6 +83,8 @@ module Honyomi
81
83
  results << <<EOF
82
84
  id: #{book.id.to_s}
83
85
  title: #{book.title}
86
+ author: #{book.author}
87
+ url: #{book.url}
84
88
  path: #{book.path}
85
89
  pages: #{book.page_num}
86
90
  timestamp: #{book.timestamp}
@@ -1,25 +1,36 @@
1
1
  require 'honyomi'
2
+ require 'honyomi/query'
2
3
  require 'grn_mini'
3
4
 
4
5
  module Honyomi
6
+ class HonyomiError < Exception ; end
7
+
5
8
  class Database
6
9
  attr_reader :books
7
10
  attr_reader :pages
11
+ attr_reader :bookmarks
8
12
 
9
13
  def initialize
10
14
  @books = GrnMini::Array.new("Books")
11
15
  @pages = GrnMini::Hash.new("Pages")
16
+ @bookmarks = GrnMini::Hash.new("Bookmarks")
12
17
 
13
18
  @books.setup_columns(path: "",
14
19
  title: "",
15
20
  author: "",
21
+ url: "",
16
22
  page_num: 0,
17
23
  timestamp: Time.new,
18
24
  )
19
25
  @pages.setup_columns(book: @books,
20
26
  text: "",
21
27
  page_no: 0,
28
+ bookmark: @bookmarks,
22
29
  )
30
+ @bookmarks.setup_columns(page: @pages,
31
+ comment: "",
32
+ timestamp: Time.new,
33
+ )
23
34
  end
24
35
 
25
36
  def add_book(path, pages, options = {})
@@ -40,6 +51,8 @@ module Honyomi
40
51
 
41
52
  book = @books.add(path: path,
42
53
  title: title,
54
+ author: "",
55
+ url: "",
43
56
  page_num: pages.size,
44
57
  timestamp: timestamp,
45
58
  )
@@ -54,8 +67,11 @@ module Honyomi
54
67
 
55
68
  def change_book(book_id, options = {})
56
69
  book = @books[book_id]
70
+ raise HonyomiError, "Invalid book id: #{book_id}" unless book.valid_id?
57
71
 
58
72
  book.title = options[:title] if options[:title]
73
+ book.author = options[:author] if options[:author]
74
+ book.url = options[:url] if options[:url]
59
75
  book.path = options[:path] if options[:path]
60
76
  book.timestamp = options[:timestamp] if options[:timestamp]
61
77
 
@@ -83,8 +99,26 @@ module Honyomi
83
99
  book.delete
84
100
  end
85
101
 
86
- def search(query)
87
- @pages.select(query, default_column: "text")
102
+ def search(query, options = {})
103
+ match_pages = @pages.select(query.page_query, default_column: "text")
104
+
105
+ if options[:cli]
106
+ snippet = match_pages.expression.snippet([ ['<<',
107
+ '>>'] ],
108
+ {normalize: true})
109
+ else
110
+ snippet = match_pages.expression.snippet([["<span class=\"highlight\">", "</span>"]], {html_escape: true, normalize: true, max_results: 5})
111
+ end
112
+
113
+ match_bookmarks = @bookmarks.select do |record|
114
+ record.match(query.bookmark_query) do |target|
115
+ target.comment * 10
116
+ end
117
+ end
118
+
119
+ group_by_page = match_bookmarks.group("page")
120
+
121
+ return group_by_page.union!(match_pages), snippet
88
122
  end
89
123
 
90
124
  def book_pages(book_id)
@@ -100,5 +134,32 @@ module Honyomi
100
134
  nil
101
135
  end
102
136
  end
137
+
138
+ def add_bookmark(page)
139
+ @bookmarks["#{page.book.id}:#{page.page_no}"] = { page: page, timestamp: Time.now }
140
+ end
141
+
142
+ def delete_bookmark(page)
143
+ @bookmarks.delete { |bookmark| bookmark.page == page }
144
+ end
145
+
146
+ def update_bookmark_comment(id, page_no, comment)
147
+ bm = @bookmarks["#{id}:#{page_no}"]
148
+ bm.comment = comment
149
+ bm.timestamp = Time.now
150
+ bm
151
+ end
152
+
153
+ def bookmark?(page)
154
+ @bookmarks["#{page.book.id}:#{page.page_no}"]
155
+ end
156
+
157
+ def bookmark_from_page(page)
158
+ @bookmarks["#{page.book.id}:#{page.page_no}"]
159
+ end
160
+
161
+ def books_bookmark(book)
162
+ @bookmarks.select { |record| record.page.book == book }
163
+ end
103
164
  end
104
165
  end
@@ -0,0 +1,92 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Honyomi
4
+ class Query
5
+ attr_reader :src
6
+ attr_reader :page_query
7
+ attr_reader :bookmark_query
8
+ attr_reader :jump_page_no
9
+ attr_reader :key
10
+
11
+ OPTIONS = [
12
+ ['book' , 'b'],
13
+ ['title' , 't'],
14
+ ['page' , 'p'],
15
+ ]
16
+
17
+ def initialize(src)
18
+ @src = src
19
+ init_hash
20
+ parse
21
+ end
22
+
23
+ private
24
+
25
+ def init_hash
26
+ @key = {}
27
+
28
+ OPTIONS.flatten.each do |key|
29
+ @key[key] = []
30
+ end
31
+ end
32
+
33
+ def parse
34
+ kp = OPTIONS.flatten.join('|')
35
+ parts = @src.scan(/(-)?(?:(#{kp}):)?(?:"(.+)"|(\S+))/)
36
+
37
+ page_query = []
38
+ bookmark_query = []
39
+
40
+ parts.each do |minus, key, quoted_value, value|
41
+ if quoted_value
42
+ text = %Q|"#{quoted_value}"|
43
+ else
44
+ text = value
45
+ end
46
+
47
+ unless (key)
48
+ begin
49
+ @jump_page_no = Integer(text)
50
+ page_query << make_query(minus, text, "page_no")
51
+ bookmark_query << make_query(minus, text, "page.page_no")
52
+ rescue ArgumentError
53
+ page_query << make_query(minus, text)
54
+ bookmark_query << make_query(minus, text)
55
+ end
56
+ else
57
+ case key
58
+ when 'book', 'b'
59
+ @key['book'] << text
60
+ page_query << make_query(minus, text, "book")
61
+ bookmark_query << make_query(minus, text, "page.book")
62
+ when 'title', 't'
63
+ @key['title'] << text
64
+ page_query << make_query(minus, text, "book.title:@")
65
+ bookmark_query << make_query(minus, text, "page.book.title:@")
66
+ when 'page', 'p'
67
+ @key['page'] << text
68
+ page_query << make_query(minus, text, "page_no")
69
+ bookmark_query << make_query(minus, text, "page.book.page_no")
70
+ end
71
+ end
72
+ end
73
+
74
+ @page_query = page_query.join(" ")
75
+ @bookmark_query = bookmark_query.join(" ")
76
+ end
77
+
78
+ def make_query(minus, text, key = nil)
79
+ m = minus ? "-" : ""
80
+
81
+ if key
82
+ if key[/@$/]
83
+ "#{m}#{key}#{text}"
84
+ else
85
+ "#{m}#{key}:#{text}"
86
+ end
87
+ else
88
+ "#{m}#{text}"
89
+ end
90
+ end
91
+ end
92
+ end
data/lib/honyomi/util.rb CHANGED
@@ -39,60 +39,28 @@ module Honyomi
39
39
  end
40
40
 
41
41
  def highlight_keywords(src, keywords, css_class)
42
- # Init highlight_map
43
- hightlight_map = Array.new(src.length, nil)
44
-
45
- keywords.each do |keyword|
46
- pos = 0
47
-
48
- loop do
49
- r = src.match(/#{Regexp.escape(keyword)}/i, pos) do |m|
50
- s = m.begin(0)
51
- l = keyword.length
52
- e = s+l
53
- (s...e).each {|i| hightlight_map[i] = 1 }
54
- pos = e
55
- end
42
+ return "" if src.nil?
43
+ return src if keywords.nil?
56
44
 
57
- break if r.nil?
58
- end
59
- end
60
-
61
- # Delete html tag
62
- index = 0
63
- in_tag = false
64
- src.each_char do |char|
65
- in_tag = true if char == '<'
66
- hightlight_map[index] = nil if in_tag
67
- in_tag = false if char == '>'
68
- index += 1
45
+ words = nil
46
+ if Groonga::VERSION[0] >= 3
47
+ words = Groonga::PatriciaTrie.create(key_type: "ShortText", normalizer: "NormalizerAuto")
48
+ else
49
+ words = Groonga::PatriciaTrie.create(key_type: "ShortText", key_normalize: true)
69
50
  end
51
+ keywords.each { |keword| words.add(keword) }
70
52
 
71
- # Output
72
- result = ""
53
+ other_text_handler = Proc.new { |string| ERB::Util.h(string) }
54
+ options = { other_text_handler: other_text_handler }
73
55
 
74
- index = 0
75
- prev = nil
76
- src.each_char do |char|
77
- current = hightlight_map[index]
78
-
79
- if prev.nil? && current
80
- result += "<span class='#{css_class}'>"
81
- elsif prev && current.nil?
82
- result += "</span>"
83
- end
84
-
85
- result += char
86
-
87
- index += 1
88
- prev = current
56
+ words.tag_keys(src, options) do |record, word|
57
+ "<span class='#{css_class}'>#{ERB::Util.h(word)}</span>"
89
58
  end
90
- result += "</span>" if prev
91
-
92
- result
93
59
  end
94
60
 
95
61
  def extract_keywords(query)
62
+ return [] if query.nil?
63
+
96
64
  query.split.reduce([]) do |a, e|
97
65
  e = e.gsub(/^\(|\)|AND|OR$/, "")
98
66
 
@@ -103,9 +71,28 @@ module Honyomi
103
71
  elsif e =~ /:/
104
72
  a
105
73
  else
106
- a + [e]
74
+ if e.empty?
75
+ a
76
+ else
77
+ a + [e]
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ def render_bookmark_comment_to_html(bookmark)
84
+ comment = CGI.escape_html(bookmark.comment || "")
85
+
86
+ URI.extract(comment, %w{http https}).uniq.each do |uri|
87
+ unless uri.match(/(\.jpg|\.jpeg|\.png)/)
88
+ comment.gsub!(uri, %Q{<a href="#{uri}">#{uri}</a>})
107
89
  end
108
90
  end
91
+
92
+ comment.gsub!(/P([1-9][0-9]*)/, %Q(<a href="/v/#{bookmark.page.book.id}?page=\\1">P\\1</a>))
93
+
94
+ comment.gsub("\n", "<br/>")
109
95
  end
96
+
110
97
  end
111
98
  end
@@ -1,3 +1,3 @@
1
1
  module Honyomi
2
- VERSION = "0.2.0"
2
+ VERSION = "1.0.0"
3
3
  end