epub-search 0.0.1
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 +17 -0
- data/.yardopts +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.markdown +53 -0
- data/Rakefile +9 -0
- data/app/add.rb +12 -0
- data/app/init.rb +14 -0
- data/app/list.rb +9 -0
- data/app/remove.rb +10 -0
- data/app/search.rb +14 -0
- data/app/server.rb +9 -0
- data/app/watch.rb +91 -0
- data/bin/epub-search +66 -0
- data/epub-search.gemspec +37 -0
- data/lib/epub/search.rb +29 -0
- data/lib/epub/search/database.rb +120 -0
- data/lib/epub/search/formatter.rb +1 -0
- data/lib/epub/search/formatter/cli.rb +34 -0
- data/lib/epub/search/server.rb +33 -0
- data/lib/epub/search/version.rb +5 -0
- data/template/index.html.erb +12 -0
- data/template/result.html.erb +16 -0
- data/test/helper.rb +3 -0
- data/test/test_database.rb +7 -0
- metadata +282 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: a0e5eaac93572491de5dfb8b483d996daf3f2798
         | 
| 4 | 
            +
              data.tar.gz: 12fd51e95e4ca7291b92ca3d10f8b5f43c76331c
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 7bab11cd12dc7f248b8dcc3f990e45c3d7c77a798750fa0eb2b88e4c915b7926675b4c6e3d73b79bc9ad21106350cdab9c34e88f6c3e2726c0dcb38ed5cf622f
         | 
| 7 | 
            +
              data.tar.gz: 64882ff476229d0841e126b9fb65c986a100e551fd39ccc0651845c0ad443eef0c554047ffac43a3f143d93e96d6fff8b230d9b77d55abba7abadb3754b45ac8
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.yardopts
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            Copyright (c) 2013 KITAITI Makoto
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            MIT License
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 6 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 7 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 8 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 9 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 10 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 11 | 
            +
            the following conditions:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 14 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 17 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 18 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 19 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 20 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 21 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 22 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README.markdown
    ADDED
    
    | @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            EPUB Search
         | 
| 2 | 
            +
            ===========
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            Search engine for EPUB files on local machine
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Installation
         | 
| 7 | 
            +
            ------------
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                $ gem install epub-search
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Usage
         | 
| 12 | 
            +
            -----
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                $ epub-search help
         | 
| 15 | 
            +
                Commands:
         | 
| 16 | 
            +
                  epub-search add FILE                           # Add FILE to database
         | 
| 17 | 
            +
                  epub-search help [COMMAND]                     # Describe available commands or one specific command
         | 
| 18 | 
            +
                  epub-search init [DB_DIR]                      # Setup database
         | 
| 19 | 
            +
                  epub-search list                               # Show list of book titles in database
         | 
| 20 | 
            +
                  epub-search remove FILE                        # Remove FILE from database
         | 
| 21 | 
            +
                  epub-search search WORD [BOOK]                 # Search WORD in book whose title is like BOOK from database
         | 
| 22 | 
            +
                  epub-search server                             # Run server
         | 
| 23 | 
            +
                  epub-search watch [DIRECTORY [DIRECTORY ...]]  # Index all of EPUB files in DIRECTORY
         | 
| 24 | 
            +
                
         | 
| 25 | 
            +
                Options:
         | 
| 26 | 
            +
                  -c, [--config=CONFIG]  # Path to config file
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            To watch directories in backend:
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                $ epub-search watch >/dev/null 2>&1 &
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            Configuration
         | 
| 33 | 
            +
            -------------
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            EPUB Search(`epub-search` command) detectes configuration file following by this order:
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            1. A file specified by `--config` global option
         | 
| 38 | 
            +
            2. `.epub-searchrc` in current directory
         | 
| 39 | 
            +
            3. `$HOME/.epub-search/config.yaml`
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            Configuration file should be written as YAML and you can set properties below:
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            * :db_dir: String. Groonga database directory, defaults to $HOME/.epub-search/db
         | 
| 44 | 
            +
            * :directories: Array of String. Directories `watch` subcommand watches.
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            Contributing
         | 
| 47 | 
            +
            ------------
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            1. Fork it
         | 
| 50 | 
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         | 
| 51 | 
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         | 
| 52 | 
            +
            4. Push to the branch (`git push origin my-new-feature`)
         | 
| 53 | 
            +
            5. Create new Pull Request
         | 
    
        data/Rakefile
    ADDED
    
    
    
        data/app/add.rb
    ADDED
    
    | @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            class Add
         | 
| 2 | 
            +
              def initialize(db_dir, file_path)
         | 
| 3 | 
            +
                @file_path = Pathname.new(file_path)
         | 
| 4 | 
            +
                raise "File not readable: #{@file_path}" unless @file_path.readable?
         | 
| 5 | 
            +
                @db = EPUB::Search::Database.new(db_dir)
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def run(update=true)
         | 
| 9 | 
            +
                @db.remove @file_path if update
         | 
| 10 | 
            +
                @db.add @file_path
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
    
        data/app/init.rb
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            class Init
         | 
| 2 | 
            +
              def initialize(db_dir)
         | 
| 3 | 
            +
                @db = EPUB::Search::Database.new(db_dir)
         | 
| 4 | 
            +
              end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def run(force=false)
         | 
| 7 | 
            +
                $stderr.puts "create database #{@db.db_file}"
         | 
| 8 | 
            +
                @db.init force
         | 
| 9 | 
            +
                if force
         | 
| 10 | 
            +
                  exit_time_file = @db.db_dir.join('../exittime')
         | 
| 11 | 
            +
                  exit_time_file.delete if exit_time_file.exist?
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
    
        data/app/list.rb
    ADDED
    
    
    
        data/app/remove.rb
    ADDED
    
    
    
        data/app/search.rb
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            class Search
         | 
| 2 | 
            +
              def initialize(db_dir, search_word, book=nil)
         | 
| 3 | 
            +
                @word, @book = search_word, book
         | 
| 4 | 
            +
                @db = EPUB::Search::Database.new(db_dir)
         | 
| 5 | 
            +
              end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              def run(color=$stdout.tty?)
         | 
| 8 | 
            +
                highlight = [true, 'always'].include? color
         | 
| 9 | 
            +
                highlight = $stdout.tty? if color == 'auto'
         | 
| 10 | 
            +
                @db.search @word, @book do |result|
         | 
| 11 | 
            +
                  EPUB::Search::Formatter::CLI.new(result, @word, highlight).format
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
    
        data/app/server.rb
    ADDED
    
    
    
        data/app/watch.rb
    ADDED
    
    | @@ -0,0 +1,91 @@ | |
| 1 | 
            +
            require 'notify'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class Watch
         | 
| 4 | 
            +
              EPUB_RE = /\.epub\Z/io
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def initialize(db_file, directories)
         | 
| 7 | 
            +
                raise ArgumentError, 'specify at least one directory' if directories.empty?
         | 
| 8 | 
            +
                @directories = directories
         | 
| 9 | 
            +
                @db = EPUB::Search::Database.new(db_file)
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def run
         | 
| 13 | 
            +
                $PROGRAM_NAME = File.basename($PROGRAM_NAME)
         | 
| 14 | 
            +
                $stderr.puts 'start to watch:'
         | 
| 15 | 
            +
                @directories.each do |dir|
         | 
| 16 | 
            +
                  $stderr.puts "  * #{dir}"
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
                catch_up
         | 
| 19 | 
            +
                begin
         | 
| 20 | 
            +
                  Listen.to *@directories, :filter => EPUB_RE do |modified, added, removed|
         | 
| 21 | 
            +
                    modified.each do |file_path|
         | 
| 22 | 
            +
                      next unless file_path =~ EPUB_RE
         | 
| 23 | 
            +
                      file_path.force_encoding 'UTF-8'
         | 
| 24 | 
            +
                      begin
         | 
| 25 | 
            +
                        @db.remove file_path
         | 
| 26 | 
            +
                        @db.add file_path
         | 
| 27 | 
            +
                        title = EPUB::Parser.parse(file_path).title
         | 
| 28 | 
            +
                        notify %Q|UPDATED: #{title}\n#{file_path}|
         | 
| 29 | 
            +
                      rescue => error
         | 
| 30 | 
            +
                        $stderr.puts error
         | 
| 31 | 
            +
                      end
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                    added.each do |file_path|
         | 
| 34 | 
            +
                      next unless file_path =~ EPUB_RE
         | 
| 35 | 
            +
                      file_path.force_encoding 'UTF-8'
         | 
| 36 | 
            +
                      begin
         | 
| 37 | 
            +
                        @db.add file_path
         | 
| 38 | 
            +
                        title = EPUB::Parser.parse(file_path).title
         | 
| 39 | 
            +
                        notify %Q|ADDED: #{title}\n#{file_path}|
         | 
| 40 | 
            +
                      rescue => error
         | 
| 41 | 
            +
                        $stderr.puts error
         | 
| 42 | 
            +
                      end
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                    removed.each do |file_path|
         | 
| 45 | 
            +
                      next unless file_path =~ EPUB_RE
         | 
| 46 | 
            +
                      file_path.force_encoding 'UTF-8'
         | 
| 47 | 
            +
                      begin
         | 
| 48 | 
            +
                        @db.remove file_path
         | 
| 49 | 
            +
                        notify %Q|REMOVED:\n#{file_path}|
         | 
| 50 | 
            +
                      rescue => error
         | 
| 51 | 
            +
                        $stderr.puts error
         | 
| 52 | 
            +
                      end
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                ensure
         | 
| 56 | 
            +
                  FileUtils.touch exit_time_file
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
              private
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              def exit_time
         | 
| 63 | 
            +
                @exittime ||= File.mtime(exit_time_file)
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              def exit_time_file
         | 
| 67 | 
            +
                @db.db_dir.join('../exittime').to_path
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              def catch_up
         | 
| 71 | 
            +
                @directories.each do |dir|
         | 
| 72 | 
            +
                  Dir["#{dir}/**/*.epub"].each do |file_path|
         | 
| 73 | 
            +
                    next if File.file? exit_time_file and File.mtime(file_path) < exit_time
         | 
| 74 | 
            +
                    begin
         | 
| 75 | 
            +
                      removed = @db.remove(file_path)
         | 
| 76 | 
            +
                      @db.add file_path
         | 
| 77 | 
            +
                      operation = removed.zero? ? 'ADDED' : 'UPDATED'
         | 
| 78 | 
            +
                      title = EPUB::Parser.parse(file_path).title
         | 
| 79 | 
            +
                      notify "#{operation}: #{title}\n#{file_path}"
         | 
| 80 | 
            +
                    rescue => error
         | 
| 81 | 
            +
                      $stderr.puts error
         | 
| 82 | 
            +
                    end
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
              end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
              def notify(message)
         | 
| 88 | 
            +
                $stderr.puts message
         | 
| 89 | 
            +
                Notify.notify $PROGRAM_NAME, message
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
            end
         | 
    
        data/bin/epub-search
    ADDED
    
    | @@ -0,0 +1,66 @@ | |
| 1 | 
            +
            require 'pathname'
         | 
| 2 | 
            +
            require 'yaml'
         | 
| 3 | 
            +
            require 'thor'
         | 
| 4 | 
            +
            require 'epub/search'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Class.new(Thor) {
         | 
| 7 | 
            +
              APP_DIR = File.expand_path('../../app', __FILE__)
         | 
| 8 | 
            +
              Dir["#{APP_DIR}/*.rb"].each do |path|
         | 
| 9 | 
            +
                require path
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              class << self
         | 
| 13 | 
            +
                def exit_on_failure?
         | 
| 14 | 
            +
                  true
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              class_option :config, :type => :string, :aliases => '-c', :default => nil, :desc => 'Path to config file'
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              method_option :force, :type => :boolean, :aliases => '-f', :default => false, :desc => 'Remove existing database before init'
         | 
| 21 | 
            +
              desc 'init [DB_DIR]', 'Setup database'
         | 
| 22 | 
            +
              def init(db_dir=config[:db_dir])
         | 
| 23 | 
            +
                Init.new(db_dir).run(options[:force])
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              method_option :update, :type => :boolean, :default => true, :desc => 'Remove existing indices of given book before adding'
         | 
| 27 | 
            +
              desc 'add FILE', 'Add FILE to database'
         | 
| 28 | 
            +
              def add(file)
         | 
| 29 | 
            +
                Add.new(config[:db_dir], file).run(options[:update])
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              method_option :color, :type => :string, :aliasis => :colour, :default => 'auto', :desc => 'Color search word in search result. auto, always and never is available. --no-color also is available as never', :banner => 'WHEN'
         | 
| 33 | 
            +
              desc 'search WORD [BOOK]', 'Search WORD in book whose title is like BOOK from database'
         | 
| 34 | 
            +
              def search(word, book=nil)
         | 
| 35 | 
            +
                raise 'Invalid argument for color option' unless [nil, 'auto', 'always', 'never'].include? options[:color]
         | 
| 36 | 
            +
                Search.new(config[:db_dir], word, book).run(options[:color])
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              desc 'watch [DIRECTORY [DIRECTORY ...]]', 'Index all of EPUB files in DIRECTORY'
         | 
| 40 | 
            +
              def watch(*directories)
         | 
| 41 | 
            +
                directories = config[:directories] if directories.empty?
         | 
| 42 | 
            +
                Watch.new(config[:db_dir], directories).run
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              desc 'remove FILE', 'Remove FILE from database'
         | 
| 46 | 
            +
              def remove(file)
         | 
| 47 | 
            +
                Remove.new(config[:db_dir], file).run
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              desc 'server', 'Run server'
         | 
| 51 | 
            +
              def server
         | 
| 52 | 
            +
                Server.new(config[:db_dir]).run
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              method_option :path, :typ => :boolean, :aliases => '-p', :default => false, :desc => 'Swho book paths'
         | 
| 56 | 
            +
              desc 'list', 'Show list of book titles in database'
         | 
| 57 | 
            +
              def list
         | 
| 58 | 
            +
                List.new(config[:db_dir]).run(options[:path])
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              private
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              def config
         | 
| 64 | 
            +
                EPUB::Search.config(options[:config])
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
            }.start
         | 
    
        data/epub-search.gemspec
    ADDED
    
    | @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            +
            lib = File.expand_path('../lib', __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 4 | 
            +
            require 'epub/search/version'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |gem|
         | 
| 7 | 
            +
              gem.name          = "epub-search"
         | 
| 8 | 
            +
              gem.version       = EPUB::Search::VERSION
         | 
| 9 | 
            +
              gem.authors       = ["KITAITI Makoto"]
         | 
| 10 | 
            +
              gem.email         = ["KitaitiMakoto@gmail.com"]
         | 
| 11 | 
            +
              gem.description   = %q{Provides tool and library of full text search for EPUB books}
         | 
| 12 | 
            +
              gem.summary       = %q{Full text search for EPUB books}
         | 
| 13 | 
            +
              # gem.homepage      = ""
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              gem.files         = `git ls-files`.split($/)
         | 
| 16 | 
            +
              gem.executables   = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
         | 
| 17 | 
            +
              gem.test_files    = gem.files.grep(%r{^(test|spec|features)/})
         | 
| 18 | 
            +
              gem.require_paths = ["lib"]
         | 
| 19 | 
            +
              gem.has_rdoc      = 'yard'
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              gem.add_runtime_dependency 'epub-parser'
         | 
| 22 | 
            +
              gem.add_runtime_dependency 'rroonga'
         | 
| 23 | 
            +
              gem.add_runtime_dependency 'thor'
         | 
| 24 | 
            +
              gem.add_runtime_dependency 'rb-inotify'
         | 
| 25 | 
            +
              gem.add_runtime_dependency 'listen'
         | 
| 26 | 
            +
              gem.add_runtime_dependency 'highline'
         | 
| 27 | 
            +
              gem.add_runtime_dependency 'notify'
         | 
| 28 | 
            +
              gem.add_runtime_dependency 'rack'
         | 
| 29 | 
            +
              gem.add_runtime_dependency 'tilt'
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              gem.add_development_dependency 'rake'
         | 
| 32 | 
            +
              gem.add_development_dependency 'bundler'
         | 
| 33 | 
            +
              gem.add_development_dependency 'test-unit'
         | 
| 34 | 
            +
              gem.add_development_dependency 'test-unit-notify'
         | 
| 35 | 
            +
              gem.add_development_dependency 'yard'
         | 
| 36 | 
            +
              gem.add_development_dependency 'redcarpet'
         | 
| 37 | 
            +
            end
         | 
    
        data/lib/epub/search.rb
    ADDED
    
    | @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            require 'epub/search/version'
         | 
| 2 | 
            +
            require 'shellwords'
         | 
| 3 | 
            +
            require 'epub/parser'
         | 
| 4 | 
            +
            require 'groonga'
         | 
| 5 | 
            +
            require 'listen'
         | 
| 6 | 
            +
            require 'highline'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module EPUB
         | 
| 9 | 
            +
              module Search
         | 
| 10 | 
            +
                DEFAULT_CONFIG = {
         | 
| 11 | 
            +
                  :config_path => File.join(Dir.home, '.epub-search/config.yaml'),
         | 
| 12 | 
            +
                  :db_dir      => File.join(Dir.home, '.epub-search/db')
         | 
| 13 | 
            +
                }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                class << self
         | 
| 16 | 
            +
                  def config(config_file=nil)
         | 
| 17 | 
            +
                    return @config if @config
         | 
| 18 | 
            +
                    config_file = config_file ||
         | 
| 19 | 
            +
                      (File.file?('.epub-searchrc') ? '.epub-searchrc' : DEFAULT_CONFIG[:config_path])
         | 
| 20 | 
            +
                    conf = YAML.load_file(config_file) if File.file? config_file
         | 
| 21 | 
            +
                    @config = DEFAULT_CONFIG.merge(conf || {})
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            require 'epub/search/database'
         | 
| 28 | 
            +
            require 'epub/search/formatter'
         | 
| 29 | 
            +
            require 'epub/search/server'
         | 
| @@ -0,0 +1,120 @@ | |
| 1 | 
            +
            module EPUB
         | 
| 2 | 
            +
              module Search
         | 
| 3 | 
            +
                class Database
         | 
| 4 | 
            +
                  FILE_NAME = 'epub-search.db'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  attr_reader :db_dir
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def initialize(db_dir)
         | 
| 9 | 
            +
                    @db_dir = Pathname === db_dir ? db_dir : Pathname.new(db_dir)
         | 
| 10 | 
            +
                    Groonga::Context.default_options = {:encoding => :utf8}
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def db_file
         | 
| 14 | 
            +
                    @db_file ||= @db_dir + FILE_NAME
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def pages
         | 
| 18 | 
            +
                    Groonga['Pages']
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def init(force=false)
         | 
| 22 | 
            +
                    @db_dir.rmtree if force
         | 
| 23 | 
            +
                    @db_dir.mkpath
         | 
| 24 | 
            +
                    Groonga::Database.create :path => db_file.to_path
         | 
| 25 | 
            +
                    Groonga::Schema.create_table 'Pages', :type => :array
         | 
| 26 | 
            +
                    Groonga::Schema.change_table 'Pages' do |table|
         | 
| 27 | 
            +
                      table.text 'location' # file path or URI
         | 
| 28 | 
            +
                      table.text 'iri' # inner IRI
         | 
| 29 | 
            +
                      table.text 'book_title'
         | 
| 30 | 
            +
                      table.text 'page_title'
         | 
| 31 | 
            +
                      table.text 'metadata'
         | 
| 32 | 
            +
                      table.text 'content'
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                    Groonga::Schema.create_table 'Terms',
         | 
| 35 | 
            +
                    :type => :patricia_trie,
         | 
| 36 | 
            +
                    :normalizer => :NormalizerAuto,
         | 
| 37 | 
            +
                    :default_tokenizer => 'TokenBigram'
         | 
| 38 | 
            +
                    Groonga::Schema.change_table 'Terms' do |table|
         | 
| 39 | 
            +
                      table.index 'Pages.book_title'
         | 
| 40 | 
            +
                      table.index 'Pages.metadata'
         | 
| 41 | 
            +
                      table.index 'Pages.content'
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  # @param [Pathname|String] path path of book
         | 
| 46 | 
            +
                  # @return [Integer] the number of added recoreds
         | 
| 47 | 
            +
                  def add(file_path)
         | 
| 48 | 
            +
                    file_path = Pathname.new(file_path) unless file_path.kind_of? Pathname
         | 
| 49 | 
            +
                    location = file_path.expand_path
         | 
| 50 | 
            +
                    book = EPUB::Parser.parse(location)
         | 
| 51 | 
            +
                    record_count = 0
         | 
| 52 | 
            +
                    open do
         | 
| 53 | 
            +
                      book.each_content do |content|
         | 
| 54 | 
            +
                        next unless content.media_type == 'application/xhtml+xml'
         | 
| 55 | 
            +
                        doc = Nokogiri.XML(content.read)
         | 
| 56 | 
            +
                        page_title = doc.search('title').first.text
         | 
| 57 | 
            +
                        body = Nokogiri.XML(doc.search('body').first.to_xml).content
         | 
| 58 | 
            +
                        pages.add('location'   => location.to_s,
         | 
| 59 | 
            +
                                  'iri'        => content.href.to_s,
         | 
| 60 | 
            +
                                  'book_title' => book.title,
         | 
| 61 | 
            +
                                  'page_title' => page_title,
         | 
| 62 | 
            +
                                  'content'    => body)
         | 
| 63 | 
            +
                        record_count += 1
         | 
| 64 | 
            +
                      end
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                    record_count
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  # @param [Pathname|String] file_path path of book
         | 
| 70 | 
            +
                  # @return [Integer] the number of removed recoreds
         | 
| 71 | 
            +
                  def remove(file_path)
         | 
| 72 | 
            +
                    file_path = Pathname.new(file_path) unless file_path.kind_of? Pathname
         | 
| 73 | 
            +
                    location = file_path.expand_path.to_path
         | 
| 74 | 
            +
                    record_count = 0
         | 
| 75 | 
            +
                    open do
         | 
| 76 | 
            +
                      records = pages.select {|record|
         | 
| 77 | 
            +
                        record.location == location
         | 
| 78 | 
            +
                      }
         | 
| 79 | 
            +
                      records.each do |record|
         | 
| 80 | 
            +
                        record.key.delete
         | 
| 81 | 
            +
                        record_count += 1
         | 
| 82 | 
            +
                      end
         | 
| 83 | 
            +
                    end
         | 
| 84 | 
            +
                    record_count
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  # @param [String] word search word
         | 
| 88 | 
            +
                  # @param [String] book book title
         | 
| 89 | 
            +
                  # @yieldparam [Hash] result search result.
         | 
| 90 | 
            +
                  #             the key is file path and the value is an array of records
         | 
| 91 | 
            +
                  def search(word, book=nil)
         | 
| 92 | 
            +
                    open do
         | 
| 93 | 
            +
                      result = pages.select {|record|
         | 
| 94 | 
            +
                        conditions = [record.content =~ word]
         | 
| 95 | 
            +
                        conditions << (record.book_title =~ book) if book
         | 
| 96 | 
            +
                        conditions
         | 
| 97 | 
            +
                      }.group_by(&:location)
         | 
| 98 | 
            +
                      yield result
         | 
| 99 | 
            +
                    end
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  def books(path=false)
         | 
| 103 | 
            +
                    open do
         | 
| 104 | 
            +
                      pages.group_by(&:location).collect {|location, records|
         | 
| 105 | 
            +
                        result  =records.first.book_title
         | 
| 106 | 
            +
                        result << " - #{location}" if path
         | 
| 107 | 
            +
                      }
         | 
| 108 | 
            +
                    end
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  private
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                  def open
         | 
| 114 | 
            +
                    Groonga::Database.open db_file.to_path do |database|
         | 
| 115 | 
            +
                      yield database
         | 
| 116 | 
            +
                    end
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
              end
         | 
| 120 | 
            +
            end
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            require 'epub/search/formatter/cli'
         | 
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            module EPUB
         | 
| 2 | 
            +
              module Search
         | 
| 3 | 
            +
                module Formatter
         | 
| 4 | 
            +
                  class CLI
         | 
| 5 | 
            +
                    def initialize(data, word, highlight=false)
         | 
| 6 | 
            +
                      @data, @word, @highlight = data, word, highlight
         | 
| 7 | 
            +
                    end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    def format
         | 
| 10 | 
            +
                      word_re = /(?<word>#{Regexp.escape(@word)})/io
         | 
| 11 | 
            +
                      highlighter = HighLine.Style(:red, :bold) if highlight?
         | 
| 12 | 
            +
                      gray = HighLine.Style(:gray) if highlight?
         | 
| 13 | 
            +
                      @data.each_pair do |location, records|
         | 
| 14 | 
            +
                        records.each do |record|
         | 
| 15 | 
            +
                          record.content.each_line do |line|
         | 
| 16 | 
            +
                            next unless line =~ word_re
         | 
| 17 | 
            +
                            result = line.chomp
         | 
| 18 | 
            +
                            result.gsub! word_re, highlighter.color($~[:word]) if highlight?
         | 
| 19 | 
            +
                            book_info = "[#{record.page_title}(#{record.book_title}): #{location} - #{record.iri}]"
         | 
| 20 | 
            +
                            book_info = gray.color(book_info)
         | 
| 21 | 
            +
                            result << book_info
         | 
| 22 | 
            +
                            puts result
         | 
| 23 | 
            +
                          end
         | 
| 24 | 
            +
                        end
         | 
| 25 | 
            +
                      end
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    def highlight?
         | 
| 29 | 
            +
                      @highlight
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
            end
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            require 'rack'
         | 
| 2 | 
            +
            require 'tilt'
         | 
| 3 | 
            +
            require 'erb'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module EPUB
         | 
| 6 | 
            +
              module Search
         | 
| 7 | 
            +
                class Server
         | 
| 8 | 
            +
                  include ERB::Util
         | 
| 9 | 
            +
                  TEMPLATE_DIR = File.join(__dir__, '../../../template')
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  # @param [Database] database
         | 
| 12 | 
            +
                  def initialize(database)
         | 
| 13 | 
            +
                    @db = database
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def call(env)
         | 
| 17 | 
            +
                    @env = env
         | 
| 18 | 
            +
                    @request = Rack::Request.new(@env)
         | 
| 19 | 
            +
                    @response = Rack::Response.new
         | 
| 20 | 
            +
                    @query = @request['query']
         | 
| 21 | 
            +
                    if @query
         | 
| 22 | 
            +
                      @db.search @query do |result|
         | 
| 23 | 
            +
                        @result = result
         | 
| 24 | 
            +
                        @search_result = Tilt.new(File.join(TEMPLATE_DIR, 'result.html.erb')).render(self)
         | 
| 25 | 
            +
                      end
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
                    @response.headers['Content-Type'] = 'text/html; charset=UTF-8'
         | 
| 28 | 
            +
                    @response.body = Tilt.new(File.join(TEMPLATE_DIR, 'index.html.erb')).render(self).each_line
         | 
| 29 | 
            +
                    @response.finish
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            <!DOCTYPE html>
         | 
| 2 | 
            +
            <title>EPUB Search</title>
         | 
| 3 | 
            +
            <style type="text/css">
         | 
| 4 | 
            +
              em {color: red; font-weight: bold; font-style: normal;}
         | 
| 5 | 
            +
              td {border-bottom: solid black thin;}
         | 
| 6 | 
            +
            </style>
         | 
| 7 | 
            +
            <h1>EPUB Search</h1>
         | 
| 8 | 
            +
            <form methdo="get">
         | 
| 9 | 
            +
              <input name="query" type="search" value="<%= @query %>">
         | 
| 10 | 
            +
              <input type="submit">
         | 
| 11 | 
            +
            </form>
         | 
| 12 | 
            +
            <%= @search_result %>
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            <table>
         | 
| 2 | 
            +
              <tr><th>book</th><th>line</th><th>location</th></tr>
         | 
| 3 | 
            +
              <% @result.each_pair do |location, records| %>
         | 
| 4 | 
            +
                <% records.each do |record| %>
         | 
| 5 | 
            +
                  <% record['content'].each_line do |line| %>
         | 
| 6 | 
            +
                    <% if line =~ /(?<query>#{Regexp.escape(@query)})/io %>
         | 
| 7 | 
            +
                      <tr>
         | 
| 8 | 
            +
                        <td><a href="file://<%=h location%>" title="<%=h record['book_title'] %>"><%=h record['book_title'] %></a></td>
         | 
| 9 | 
            +
                        <td><%=h(line).gsub /(?<query>#{Regexp.escape(@query)})/io, "<em>#{h $~[:query]}</em>" %></td>
         | 
| 10 | 
            +
                        <td><a href="file://<%=h location %>" title="<%=h record['book_title'] %>"><%=h location %></a></td>
         | 
| 11 | 
            +
                      </tr>
         | 
| 12 | 
            +
                    <% end %>
         | 
| 13 | 
            +
                  <% end %>
         | 
| 14 | 
            +
                <% end %>
         | 
| 15 | 
            +
              <% end %>
         | 
| 16 | 
            +
            </table>
         | 
    
        data/test/helper.rb
    ADDED
    
    
    
        metadata
    ADDED
    
    | @@ -0,0 +1,282 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: epub-search
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.0.1
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - KITAITI Makoto
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2013-03-30 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: epub-parser
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - '>='
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '0'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - '>='
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '0'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: rroonga
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - '>='
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '0'
         | 
| 34 | 
            +
              type: :runtime
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - '>='
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '0'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: thor
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - '>='
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '0'
         | 
| 48 | 
            +
              type: :runtime
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - '>='
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: rb-inotify
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - '>='
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '0'
         | 
| 62 | 
            +
              type: :runtime
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - '>='
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '0'
         | 
| 69 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 70 | 
            +
              name: listen
         | 
| 71 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 | 
            +
                requirements:
         | 
| 73 | 
            +
                - - '>='
         | 
| 74 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            +
                    version: '0'
         | 
| 76 | 
            +
              type: :runtime
         | 
| 77 | 
            +
              prerelease: false
         | 
| 78 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 | 
            +
                requirements:
         | 
| 80 | 
            +
                - - '>='
         | 
| 81 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            +
                    version: '0'
         | 
| 83 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            +
              name: highline
         | 
| 85 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            +
                requirements:
         | 
| 87 | 
            +
                - - '>='
         | 
| 88 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            +
                    version: '0'
         | 
| 90 | 
            +
              type: :runtime
         | 
| 91 | 
            +
              prerelease: false
         | 
| 92 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 | 
            +
                requirements:
         | 
| 94 | 
            +
                - - '>='
         | 
| 95 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            +
                    version: '0'
         | 
| 97 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 98 | 
            +
              name: notify
         | 
| 99 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 100 | 
            +
                requirements:
         | 
| 101 | 
            +
                - - '>='
         | 
| 102 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 103 | 
            +
                    version: '0'
         | 
| 104 | 
            +
              type: :runtime
         | 
| 105 | 
            +
              prerelease: false
         | 
| 106 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 107 | 
            +
                requirements:
         | 
| 108 | 
            +
                - - '>='
         | 
| 109 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 110 | 
            +
                    version: '0'
         | 
| 111 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 112 | 
            +
              name: rack
         | 
| 113 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 114 | 
            +
                requirements:
         | 
| 115 | 
            +
                - - '>='
         | 
| 116 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 117 | 
            +
                    version: '0'
         | 
| 118 | 
            +
              type: :runtime
         | 
| 119 | 
            +
              prerelease: false
         | 
| 120 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 121 | 
            +
                requirements:
         | 
| 122 | 
            +
                - - '>='
         | 
| 123 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 124 | 
            +
                    version: '0'
         | 
| 125 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 126 | 
            +
              name: tilt
         | 
| 127 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 128 | 
            +
                requirements:
         | 
| 129 | 
            +
                - - '>='
         | 
| 130 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 131 | 
            +
                    version: '0'
         | 
| 132 | 
            +
              type: :runtime
         | 
| 133 | 
            +
              prerelease: false
         | 
| 134 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 135 | 
            +
                requirements:
         | 
| 136 | 
            +
                - - '>='
         | 
| 137 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 138 | 
            +
                    version: '0'
         | 
| 139 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 140 | 
            +
              name: rake
         | 
| 141 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 142 | 
            +
                requirements:
         | 
| 143 | 
            +
                - - '>='
         | 
| 144 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 145 | 
            +
                    version: '0'
         | 
| 146 | 
            +
              type: :development
         | 
| 147 | 
            +
              prerelease: false
         | 
| 148 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 149 | 
            +
                requirements:
         | 
| 150 | 
            +
                - - '>='
         | 
| 151 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 152 | 
            +
                    version: '0'
         | 
| 153 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 154 | 
            +
              name: bundler
         | 
| 155 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 156 | 
            +
                requirements:
         | 
| 157 | 
            +
                - - '>='
         | 
| 158 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 159 | 
            +
                    version: '0'
         | 
| 160 | 
            +
              type: :development
         | 
| 161 | 
            +
              prerelease: false
         | 
| 162 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 163 | 
            +
                requirements:
         | 
| 164 | 
            +
                - - '>='
         | 
| 165 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 166 | 
            +
                    version: '0'
         | 
| 167 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 168 | 
            +
              name: test-unit
         | 
| 169 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 170 | 
            +
                requirements:
         | 
| 171 | 
            +
                - - '>='
         | 
| 172 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 173 | 
            +
                    version: '0'
         | 
| 174 | 
            +
              type: :development
         | 
| 175 | 
            +
              prerelease: false
         | 
| 176 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 177 | 
            +
                requirements:
         | 
| 178 | 
            +
                - - '>='
         | 
| 179 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 180 | 
            +
                    version: '0'
         | 
| 181 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 182 | 
            +
              name: test-unit-notify
         | 
| 183 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 184 | 
            +
                requirements:
         | 
| 185 | 
            +
                - - '>='
         | 
| 186 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 187 | 
            +
                    version: '0'
         | 
| 188 | 
            +
              type: :development
         | 
| 189 | 
            +
              prerelease: false
         | 
| 190 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 191 | 
            +
                requirements:
         | 
| 192 | 
            +
                - - '>='
         | 
| 193 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 194 | 
            +
                    version: '0'
         | 
| 195 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 196 | 
            +
              name: yard
         | 
| 197 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 198 | 
            +
                requirements:
         | 
| 199 | 
            +
                - - '>='
         | 
| 200 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 201 | 
            +
                    version: '0'
         | 
| 202 | 
            +
              type: :development
         | 
| 203 | 
            +
              prerelease: false
         | 
| 204 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 205 | 
            +
                requirements:
         | 
| 206 | 
            +
                - - '>='
         | 
| 207 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 208 | 
            +
                    version: '0'
         | 
| 209 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 210 | 
            +
              name: redcarpet
         | 
| 211 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 212 | 
            +
                requirements:
         | 
| 213 | 
            +
                - - '>='
         | 
| 214 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 215 | 
            +
                    version: '0'
         | 
| 216 | 
            +
              type: :development
         | 
| 217 | 
            +
              prerelease: false
         | 
| 218 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 219 | 
            +
                requirements:
         | 
| 220 | 
            +
                - - '>='
         | 
| 221 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 222 | 
            +
                    version: '0'
         | 
| 223 | 
            +
            description: Provides tool and library of full text search for EPUB books
         | 
| 224 | 
            +
            email:
         | 
| 225 | 
            +
            - KitaitiMakoto@gmail.com
         | 
| 226 | 
            +
            executables:
         | 
| 227 | 
            +
            - epub-search
         | 
| 228 | 
            +
            extensions: []
         | 
| 229 | 
            +
            extra_rdoc_files: []
         | 
| 230 | 
            +
            files:
         | 
| 231 | 
            +
            - .gitignore
         | 
| 232 | 
            +
            - .yardopts
         | 
| 233 | 
            +
            - Gemfile
         | 
| 234 | 
            +
            - LICENSE.txt
         | 
| 235 | 
            +
            - README.markdown
         | 
| 236 | 
            +
            - Rakefile
         | 
| 237 | 
            +
            - app/add.rb
         | 
| 238 | 
            +
            - app/init.rb
         | 
| 239 | 
            +
            - app/list.rb
         | 
| 240 | 
            +
            - app/remove.rb
         | 
| 241 | 
            +
            - app/search.rb
         | 
| 242 | 
            +
            - app/server.rb
         | 
| 243 | 
            +
            - app/watch.rb
         | 
| 244 | 
            +
            - bin/epub-search
         | 
| 245 | 
            +
            - epub-search.gemspec
         | 
| 246 | 
            +
            - lib/epub/search.rb
         | 
| 247 | 
            +
            - lib/epub/search/database.rb
         | 
| 248 | 
            +
            - lib/epub/search/formatter.rb
         | 
| 249 | 
            +
            - lib/epub/search/formatter/cli.rb
         | 
| 250 | 
            +
            - lib/epub/search/server.rb
         | 
| 251 | 
            +
            - lib/epub/search/version.rb
         | 
| 252 | 
            +
            - template/index.html.erb
         | 
| 253 | 
            +
            - template/result.html.erb
         | 
| 254 | 
            +
            - test/helper.rb
         | 
| 255 | 
            +
            - test/test_database.rb
         | 
| 256 | 
            +
            homepage: 
         | 
| 257 | 
            +
            licenses: []
         | 
| 258 | 
            +
            metadata: {}
         | 
| 259 | 
            +
            post_install_message: 
         | 
| 260 | 
            +
            rdoc_options: []
         | 
| 261 | 
            +
            require_paths:
         | 
| 262 | 
            +
            - lib
         | 
| 263 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 264 | 
            +
              requirements:
         | 
| 265 | 
            +
              - - '>='
         | 
| 266 | 
            +
                - !ruby/object:Gem::Version
         | 
| 267 | 
            +
                  version: '0'
         | 
| 268 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 269 | 
            +
              requirements:
         | 
| 270 | 
            +
              - - '>='
         | 
| 271 | 
            +
                - !ruby/object:Gem::Version
         | 
| 272 | 
            +
                  version: '0'
         | 
| 273 | 
            +
            requirements: []
         | 
| 274 | 
            +
            rubyforge_project: 
         | 
| 275 | 
            +
            rubygems_version: 2.0.0
         | 
| 276 | 
            +
            signing_key: 
         | 
| 277 | 
            +
            specification_version: 4
         | 
| 278 | 
            +
            summary: Full text search for EPUB books
         | 
| 279 | 
            +
            test_files:
         | 
| 280 | 
            +
            - test/helper.rb
         | 
| 281 | 
            +
            - test/test_database.rb
         | 
| 282 | 
            +
            has_rdoc: yard
         |