klipbook 0.3.0 → 1.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.
- data/Gemfile +6 -5
- data/Gemfile.lock +62 -25
- data/Guardfile +1 -2
- data/README.md +66 -18
- data/Rakefile +5 -1
- data/bin/klipbook +85 -1
- data/example.png +0 -0
- data/features/collate.feature +51 -0
- data/features/fixtures/clippings-for-three-books.txt +105 -0
- data/features/list.feature +31 -0
- data/features/step_definitions/collate_steps.rb +61 -0
- data/features/step_definitions/list_steps.rb +15 -0
- data/features/support/env.rb +5 -1
- data/klipbook.gemspec +49 -32
- data/lib/klipbook/book.rb +18 -0
- data/lib/klipbook/clipping.rb +4 -10
- data/lib/klipbook/collator.rb +17 -0
- data/lib/klipbook/config.rb +22 -0
- data/lib/klipbook/fetcher.rb +29 -0
- data/lib/klipbook/invalid_source_error.rb +12 -0
- data/lib/klipbook/output/book_helpers.rb +12 -0
- data/lib/klipbook/{book_summary.erb → output/html_book_summary.erb} +65 -11
- data/lib/klipbook/output/html_summary_writer.rb +42 -0
- data/lib/klipbook/printer.rb +18 -0
- data/lib/klipbook/sources/amazon_site/book_scraper.rb +67 -0
- data/lib/klipbook/sources/amazon_site/scraper.rb +78 -0
- data/lib/klipbook/sources/kindle_device/entry.rb +11 -0
- data/lib/klipbook/sources/kindle_device/entry_parser.rb +85 -0
- data/lib/klipbook/sources/kindle_device/file.rb +57 -0
- data/lib/klipbook/sources/kindle_device/file_parser.rb +33 -0
- data/lib/klipbook/version.rb +1 -1
- data/lib/klipbook.rb +18 -5
- data/spec/lib/klipbook/book_spec.rb +33 -0
- data/spec/lib/klipbook/collator_spec.rb +40 -0
- data/spec/lib/klipbook/fetcher_spec.rb +81 -0
- data/spec/lib/klipbook/output/html_summary_writer_spec.rb +90 -0
- data/spec/lib/klipbook/printer_spec.rb +45 -0
- data/spec/lib/klipbook/sources/kindle_device/entry_parser_spec.rb +275 -0
- data/spec/lib/klipbook/sources/kindle_device/file_parser_spec.rb +68 -0
- data/spec/lib/klipbook/sources/kindle_device/file_spec.rb +163 -0
- metadata +158 -58
- data/features/list_books.feature +0 -23
- data/features/print_book_summary.feature +0 -10
- data/features/step_definitions/klipbook_steps.rb +0 -87
- data/lib/klipbook/book_summary.rb +0 -35
- data/lib/klipbook/cli.rb +0 -49
- data/lib/klipbook/clippings_file.rb +0 -50
- data/lib/klipbook/clippings_parser.rb +0 -98
- data/lib/klipbook/runner.rb +0 -29
- data/spec/lib/klipbook/book_summary_spec.rb +0 -30
- data/spec/lib/klipbook/clipping_spec.rb +0 -17
- data/spec/lib/klipbook/clippings_file_spec.rb +0 -60
- data/spec/lib/klipbook/clippings_parser_spec.rb +0 -367
- data/spec/lib/klipbook/runner_spec.rb +0 -87
| @@ -0,0 +1,85 @@ | |
| 1 | 
            +
            module Klipbook::Sources
         | 
| 2 | 
            +
              module KindleDevice
         | 
| 3 | 
            +
                class EntryParser
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                  def build_entry(entry_text)
         | 
| 6 | 
            +
                    return nil if invalid_entry?(entry_text)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                    lines = split_text_into_lines(entry_text)
         | 
| 9 | 
            +
                    title_line = lines[0].strip
         | 
| 10 | 
            +
                    metadata = lines[1].strip
         | 
| 11 | 
            +
                    text_lines = lines[3..-1]
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    type = extract_type(metadata)
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    Klipbook::Sources::KindleDevice::Entry.new do |h|
         | 
| 16 | 
            +
                      h.title = extract_title(title_line)
         | 
| 17 | 
            +
                      h.author = extract_author(title_line)
         | 
| 18 | 
            +
                      h.location = extract_location(metadata)
         | 
| 19 | 
            +
                      h.page = extract_page(metadata)
         | 
| 20 | 
            +
                      h.added_on = extract_added_date(metadata)
         | 
| 21 | 
            +
                      h.text = extract_content(text_lines)
         | 
| 22 | 
            +
                      h.type = extract_type(metadata)
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                private
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def invalid_entry?(entry_text)
         | 
| 29 | 
            +
                    entry_text.blank? || incomplete_entry?(entry_text)
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def incomplete_entry?(entry_text)
         | 
| 33 | 
            +
                    split_text_into_lines(entry_text).length < 2
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def split_text_into_lines(entry_text)
         | 
| 37 | 
            +
                    entry_text.lstrip.lines.to_a
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  def extract_title(title_line)
         | 
| 41 | 
            +
                    if title_line =~ /\(.+\)\Z/
         | 
| 42 | 
            +
                      title_line.scan(/(.*)\s+\(.+\)\Z/).first.first
         | 
| 43 | 
            +
                    else
         | 
| 44 | 
            +
                      title_line
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def extract_author(title_line)
         | 
| 49 | 
            +
                    match = title_line.scan /\(([^\(]+)\)\Z/
         | 
| 50 | 
            +
                    match.empty? ? nil : match.first.first
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  def extract_type(metadata)
         | 
| 54 | 
            +
                    type = metadata.scan(/^-( Your)? (\w+)/).first[1]
         | 
| 55 | 
            +
                    type.downcase.to_sym
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  def extract_location(metadata)
         | 
| 59 | 
            +
                    match = metadata.scan(/Loc(ation|\.) ([0-9]+-?)/)
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    return 0 if match.empty?
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    location = match.first[1]
         | 
| 64 | 
            +
                    location.to_i
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  def extract_page(metadata)
         | 
| 68 | 
            +
                    match = metadata.scan(/Page (\d+)/)
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    return nil if match.empty?
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    location = match.first.first
         | 
| 73 | 
            +
                    location.to_i
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  def extract_content(text_lines)
         | 
| 77 | 
            +
                    text_lines.join('').rstrip
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  def extract_added_date(metadata)
         | 
| 81 | 
            +
                    DateTime.parse(metadata.scan(/Added on (.+)$/i).first.first)
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
              end
         | 
| 85 | 
            +
            end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            module Klipbook::Sources
         | 
| 2 | 
            +
              module KindleDevice
         | 
| 3 | 
            +
                class File
         | 
| 4 | 
            +
                  def initialize(file_text, max_books, file_parser=FileParser.new)
         | 
| 5 | 
            +
                    @file_text = file_text
         | 
| 6 | 
            +
                    @file_parser = file_parser
         | 
| 7 | 
            +
                    @max_books = max_books
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def books
         | 
| 11 | 
            +
                    @books ||= build_books.take(@max_books)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                private
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def build_books
         | 
| 17 | 
            +
                    sorted_entries = extract_sorted_entries_from_file_text
         | 
| 18 | 
            +
                    build_sorted_book_list(sorted_entries)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def extract_sorted_entries_from_file_text
         | 
| 22 | 
            +
                    entries = @file_parser.extract_entries(@file_text)
         | 
| 23 | 
            +
                    entries.sort { |entry_a, entry_b| entry_a.title <=> entry_b.title }
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def build_sorted_book_list(sorted_entries)
         | 
| 27 | 
            +
                    books_from_entries(sorted_entries).sort do |book_a, book_b|
         | 
| 28 | 
            +
                      -(book_a.last_update <=> book_b.last_update)
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def books_from_entries(entries)
         | 
| 33 | 
            +
                    entries.select { |entry| entry.type != :bookmark }
         | 
| 34 | 
            +
                           .group_by(&:title)
         | 
| 35 | 
            +
                           .map { |title, book_entries| book_from_entries(book_entries) }
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def book_from_entries(entries)
         | 
| 39 | 
            +
                    entries.sort! { |ea, eb| ea.location <=> eb.location }
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    Klipbook::Book.new do |b|
         | 
| 42 | 
            +
                      b.title = entries.first.title
         | 
| 43 | 
            +
                      b.author = entries.first.author
         | 
| 44 | 
            +
                      b.last_update = entries.map(&:added_on).max
         | 
| 45 | 
            +
                      b.clippings = entries.map do |e|
         | 
| 46 | 
            +
                        Klipbook::Clipping.new do |c|
         | 
| 47 | 
            +
                          c.location = e.location
         | 
| 48 | 
            +
                          c.page = e.page
         | 
| 49 | 
            +
                          c.text = e.text
         | 
| 50 | 
            +
                          c.type = e.type
         | 
| 51 | 
            +
                        end
         | 
| 52 | 
            +
                      end
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            # encoding: UTF-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Klipbook::Sources
         | 
| 4 | 
            +
              module KindleDevice
         | 
| 5 | 
            +
                class FileParser
         | 
| 6 | 
            +
                  def initialize(entry_parser=EntryParser.new)
         | 
| 7 | 
            +
                    @entry_parser = entry_parser
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def extract_entries(file_text)
         | 
| 11 | 
            +
                    entries_text = split_into_raw_entries_text(file_text)
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    build_entries(entries_text)
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                private
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def build_entries(entries_text)
         | 
| 19 | 
            +
                    entries_text.map do |entry_text|
         | 
| 20 | 
            +
                      @entry_parser.build_entry(entry_text)
         | 
| 21 | 
            +
                    end.compact
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def strip_control_characters(file_text)
         | 
| 25 | 
            +
                    file_text.gsub("\r", '').gsub("\xef\xbb\xbf", '')
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def split_into_raw_entries_text(file_text)
         | 
| 29 | 
            +
                    strip_control_characters(file_text).split('==========')
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
    
        data/lib/klipbook/version.rb
    CHANGED
    
    
    
        data/lib/klipbook.rb
    CHANGED
    
    | @@ -1,10 +1,23 @@ | |
| 1 1 | 
             
            # encoding: utf-8
         | 
| 2 2 | 
             
            require 'klipbook/blank'
         | 
| 3 3 | 
             
            require 'klipbook/version'
         | 
| 4 | 
            -
             | 
| 4 | 
            +
             | 
| 5 | 
            +
            require 'klipbook/sources/kindle_device/file_parser'
         | 
| 6 | 
            +
            require 'klipbook/sources/kindle_device/entry_parser'
         | 
| 7 | 
            +
            require 'klipbook/sources/kindle_device/entry'
         | 
| 8 | 
            +
            require 'klipbook/sources/kindle_device/file'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            require 'klipbook/sources/amazon_site/scraper'
         | 
| 11 | 
            +
            require 'klipbook/sources/amazon_site/book_scraper'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            require 'klipbook/invalid_source_error'
         | 
| 14 | 
            +
            require 'klipbook/config'
         | 
| 15 | 
            +
            require 'klipbook/book'
         | 
| 5 16 | 
             
            require 'klipbook/clipping'
         | 
| 6 | 
            -
            require 'klipbook/clippings_parser'
         | 
| 7 | 
            -
            require 'klipbook/book_summary'
         | 
| 8 | 
            -
            require 'klipbook/runner'
         | 
| 9 | 
            -
            require 'klipbook/cli'
         | 
| 10 17 |  | 
| 18 | 
            +
            require 'klipbook/fetcher'
         | 
| 19 | 
            +
            require 'klipbook/collator'
         | 
| 20 | 
            +
            require 'klipbook/printer'
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            require 'klipbook/output/html_summary_writer'
         | 
| 23 | 
            +
            require 'klipbook/output/book_helpers'
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Klipbook::Book do
         | 
| 4 | 
            +
              describe '#title_and_author' do
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                subject { book.title_and_author }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                context 'with no author' do
         | 
| 9 | 
            +
                  let(:book) do
         | 
| 10 | 
            +
                    Klipbook::Book.new do |b|
         | 
| 11 | 
            +
                      b.title = 'Book title'
         | 
| 12 | 
            +
                    end
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  it 'only contains the title' do
         | 
| 16 | 
            +
                    subject.should == 'Book title'
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                context 'with an author' do
         | 
| 21 | 
            +
                  let(:book) do
         | 
| 22 | 
            +
                    Klipbook::Book.new do |b|
         | 
| 23 | 
            +
                      b.title = 'Book title'
         | 
| 24 | 
            +
                      b.author = 'Rob Ripjaw'
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  it 'contains the title and author' do
         | 
| 29 | 
            +
                    subject.should == 'Book title by Rob Ripjaw'
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Klipbook::Collator do
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              let (:it) { Klipbook::Collator.new(books, summary_writer) }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              let (:summary_writer) do
         | 
| 8 | 
            +
                Object.new.tap do |fake_writer|
         | 
| 9 | 
            +
                  stub(fake_writer).write
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              let (:message_stream) do
         | 
| 14 | 
            +
                Object.new.tap do |fake_stream|
         | 
| 15 | 
            +
                  stub(fake_stream).puts
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              let (:book_one) { Klipbook::Book.new }
         | 
| 20 | 
            +
              let (:book_two) { Klipbook::Book.new }
         | 
| 21 | 
            +
              let (:books) { [ book_one, book_two ] }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              let(:output_dir) { 'fake output dir' }
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              describe '#collate_books' do
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                subject { it.collate_books(output_dir, true, message_stream) }
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                it 'prints a message displaying the output directory' do
         | 
| 30 | 
            +
                  subject
         | 
| 31 | 
            +
                  message_stream.should have_received.puts('Using output directory: fake output dir')
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                it 'passes each book to the summary writer' do
         | 
| 35 | 
            +
                  subject
         | 
| 36 | 
            +
                  summary_writer.should have_received.write(book_one, output_dir, true)
         | 
| 37 | 
            +
                  summary_writer.should have_received.write(book_two, output_dir, true)
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| @@ -0,0 +1,81 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Klipbook::Fetcher do
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              let(:fake_source) do
         | 
| 6 | 
            +
                Object.new.tap do |fakey|
         | 
| 7 | 
            +
                  stub(fakey).books { books }
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              context 'when created with an invalid source' do
         | 
| 12 | 
            +
                it 'raises an error' do
         | 
| 13 | 
            +
                  expect { Klipbook::Fetcher.new('sdf' , 2) }.to raise_error(InvalidSourceError)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              context 'when created with a site source' do
         | 
| 18 | 
            +
                subject { fetcher }
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                let(:fetcher) { Klipbook::Fetcher.new('site:username@example.com:password', 2) }
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                before(:each) do
         | 
| 23 | 
            +
                  stub(Klipbook::Sources::AmazonSite::Scraper).new { fake_source }
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                it 'creates a site scraper with the provided credentials' do
         | 
| 27 | 
            +
                  subject
         | 
| 28 | 
            +
                  Klipbook::Sources::AmazonSite::Scraper.should have_received.new('username@example.com', 'password', 2)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                describe '#fetch_books' do
         | 
| 32 | 
            +
                  subject { fetcher.fetch_books }
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  let(:books) { [] }
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  it 'returns the books returned by the site source' do
         | 
| 37 | 
            +
                    subject.should == books
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              context 'when created with a file source' do
         | 
| 43 | 
            +
                subject { fetcher }
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                let(:fetcher) { Klipbook::Fetcher.new('file:filename', 2) }
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                let(:fake_file) do
         | 
| 48 | 
            +
                  Object.new.tap do |file|
         | 
| 49 | 
            +
                    stub(file).read { file_contents }
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                let(:file_contents) { 'fake contents ' }
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                before(:each) do
         | 
| 56 | 
            +
                  stub(Klipbook::Sources::KindleDevice::File).new { fake_source }
         | 
| 57 | 
            +
                  stub(File).open { fake_file }
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                it "reads the file's contents from disk" do
         | 
| 61 | 
            +
                  subject
         | 
| 62 | 
            +
                  File.should have_received.open('filename', 'r')
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                it 'uses the file contents to create a file source' do
         | 
| 66 | 
            +
                  subject
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  Klipbook::Sources::KindleDevice::File.should have_received.new('fake contents', 2)
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                describe '#fetch_books' do
         | 
| 72 | 
            +
                  subject { fetcher.fetch_books }
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                  let(:books) { [] }
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  it 'returns the books returned by the file source' do
         | 
| 77 | 
            +
                    subject.should == books
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
              end
         | 
| 81 | 
            +
            end
         | 
| @@ -0,0 +1,90 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # This is more of an integration test but what the heck
         | 
| 4 | 
            +
            # it can live in here for now
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            describe Klipbook::Output::HtmlSummaryWriter do
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              before(:all) do
         | 
| 9 | 
            +
                @output_dir = Dir.mktmpdir
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              after(:all) do
         | 
| 13 | 
            +
                FileUtils.rm_f(@output_dir)
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              let(:book) do
         | 
| 17 | 
            +
                Klipbook::Book.new do |b|
         | 
| 18 | 
            +
                  b.title = 'Fake book title'
         | 
| 19 | 
            +
                  b.author = 'Fake Author'
         | 
| 20 | 
            +
                  b.clippings = []
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              let(:message_stream) do
         | 
| 25 | 
            +
                Object.new.tap do |fake_stream|
         | 
| 26 | 
            +
                  stub(fake_stream).puts
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              describe '#write' do
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                subject { Klipbook::Output::HtmlSummaryWriter.new(message_stream).write(book, @output_dir, force) }
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                let(:force) { false }
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                let(:expected_filename) { "Fake book title by Fake Author.html" }
         | 
| 37 | 
            +
                let(:expected_filepath) { "#{@output_dir}/Fake book title by Fake Author.html" }
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                context 'with no existing summary file' do
         | 
| 40 | 
            +
                  before(:each) do
         | 
| 41 | 
            +
                    FileUtils.rm_f(File.join(@output_dir, '*'))
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  it 'writes a file named after the book into the output directory' do
         | 
| 45 | 
            +
                    subject
         | 
| 46 | 
            +
                    File.exists?(expected_filepath).should be_true
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  it 'writes a html summary to the file' do
         | 
| 50 | 
            +
                    subject
         | 
| 51 | 
            +
                    File.read(expected_filepath).should include("<h1>Fake book title</h1>")
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                context 'with an existing summary file' do
         | 
| 56 | 
            +
                  before(:each) do
         | 
| 57 | 
            +
                    FileUtils.rm_f(expected_filepath)
         | 
| 58 | 
            +
                    FileUtils.touch(expected_filepath)
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  context "and 'force' set to false" do
         | 
| 62 | 
            +
                    let(:force) { false }
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                    it "won't write to the file" do
         | 
| 65 | 
            +
                      subject
         | 
| 66 | 
            +
                      File.size(expected_filepath).should == 0
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                    it 'prints a message informing that the file is being skipped' do
         | 
| 70 | 
            +
                      subject
         | 
| 71 | 
            +
                      message_stream.should have_received.puts("\e[33mSkipping \e[0m#{expected_filename}")
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  context "and 'force' set to true" do
         | 
| 76 | 
            +
                    let(:force) { true }
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                    it 'overwrites the file' do
         | 
| 79 | 
            +
                      subject
         | 
| 80 | 
            +
                      File.size(expected_filepath).should > 0
         | 
| 81 | 
            +
                    end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                    it 'prints a message informing that the file is being written' do
         | 
| 84 | 
            +
                      subject
         | 
| 85 | 
            +
                      message_stream.should have_received.puts("\e[32mWriting \e[0m#{expected_filename}")
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
            end
         | 
| @@ -0,0 +1,45 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Klipbook::Printer do
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              let (:output) do
         | 
| 6 | 
            +
                Object.new.tap do |fake_output|
         | 
| 7 | 
            +
                  stub(fake_output).puts
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              describe '#print' do
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                subject { Klipbook::Printer.new(books).print(output) }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                context 'when created with no books' do
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  let (:books) { [] }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  it 'displays a message saying that the clipping file contains no books' do
         | 
| 20 | 
            +
                    subject
         | 
| 21 | 
            +
                    output.should have_received.puts('No books available')
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                context 'when created with multiple books' do
         | 
| 26 | 
            +
                  let (:books) do
         | 
| 27 | 
            +
                    [
         | 
| 28 | 
            +
                      Klipbook::Book.new { |b| b.title = 'My first fake title' },
         | 
| 29 | 
            +
                      Klipbook::Book.new { |b| b.title = 'Another fake book'; b.author = 'Rock Riphard' }
         | 
| 30 | 
            +
                    ]
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  it 'displays a message describing the book list' do
         | 
| 34 | 
            +
                    subject
         | 
| 35 | 
            +
                    output.should have_received.puts('Book list:')
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  it 'displays an indexed list of book titles including the author when available' do
         | 
| 39 | 
            +
                    subject
         | 
| 40 | 
            +
                    output.should have_received.puts('[1] My first fake title')
         | 
| 41 | 
            +
                    output.should have_received.puts('[2] Another fake book by Rock Riphard')
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
            end
         |