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
data/Gemfile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
source 'http://rubygems.org'
|
2
2
|
|
3
|
-
gem '
|
3
|
+
gem 'gli'
|
4
|
+
gem 'mechanize'
|
5
|
+
gem 'rainbow'
|
4
6
|
|
5
7
|
group :development do
|
6
8
|
gem 'rspec'
|
@@ -8,12 +10,11 @@ group :development do
|
|
8
10
|
gem 'bundler'
|
9
11
|
gem 'jeweler', '~> 1.6.4'
|
10
12
|
gem 'rcov', '>= 0'
|
13
|
+
gem 'pry'
|
11
14
|
gem 'cucumber'
|
15
|
+
gem 'aruba'
|
12
16
|
gem 'guard'
|
13
17
|
gem 'guard-rspec'
|
14
18
|
gem 'guard-cucumber'
|
15
|
-
gem '
|
16
|
-
gem 'rb-fsevent', :require => false
|
17
|
-
gem 'rb-fchange', :require => false
|
18
|
-
gem 'growl_notify'
|
19
|
+
gem 'terminal-notifier-guard' if RUBY_PLATFORM.downcase.include?('darwin12')
|
19
20
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,37 +1,68 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
+
aruba (0.4.11)
|
5
|
+
childprocess (>= 0.2.3)
|
6
|
+
cucumber (>= 1.1.1)
|
7
|
+
ffi (>= 1.0.11)
|
8
|
+
rspec (>= 2.7.0)
|
4
9
|
builder (3.0.0)
|
5
|
-
|
10
|
+
childprocess (0.3.5)
|
11
|
+
ffi (~> 1.0, >= 1.0.6)
|
12
|
+
coderay (1.0.7)
|
13
|
+
cucumber (1.2.1)
|
6
14
|
builder (>= 2.1.2)
|
7
|
-
diff-lcs (>= 1.1.
|
8
|
-
gherkin (~> 2.
|
15
|
+
diff-lcs (>= 1.1.3)
|
16
|
+
gherkin (~> 2.11.0)
|
9
17
|
json (>= 1.4.6)
|
10
|
-
term-ansicolor (>= 1.0.6)
|
11
18
|
diff-lcs (1.1.3)
|
12
|
-
|
13
|
-
|
19
|
+
domain_name (0.5.3)
|
20
|
+
unf (~> 0.0.3)
|
21
|
+
ffi (1.1.5)
|
22
|
+
gherkin (2.11.2)
|
14
23
|
json (>= 1.4.6)
|
15
24
|
git (1.2.5)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
thor (
|
20
|
-
guard-cucumber (
|
21
|
-
cucumber (>= 0
|
22
|
-
guard (>=
|
23
|
-
guard-rspec (
|
24
|
-
guard (>=
|
25
|
+
gli (2.0.0)
|
26
|
+
guard (1.3.2)
|
27
|
+
listen (>= 0.4.2)
|
28
|
+
thor (>= 0.14.6)
|
29
|
+
guard-cucumber (1.2.0)
|
30
|
+
cucumber (>= 1.2.0)
|
31
|
+
guard (>= 1.1.0)
|
32
|
+
guard-rspec (1.2.1)
|
33
|
+
guard (>= 1.1)
|
25
34
|
jeweler (1.6.4)
|
26
35
|
bundler (~> 1.0)
|
27
36
|
git (>= 1.2.5)
|
28
37
|
rake
|
29
|
-
json (1.
|
38
|
+
json (1.7.5)
|
39
|
+
listen (0.4.7)
|
40
|
+
rb-fchange (~> 0.0.5)
|
41
|
+
rb-fsevent (~> 0.9.1)
|
42
|
+
rb-inotify (~> 0.8.8)
|
43
|
+
mechanize (2.5.1)
|
44
|
+
domain_name (~> 0.5, >= 0.5.1)
|
45
|
+
mime-types (~> 1.17, >= 1.17.2)
|
46
|
+
net-http-digest_auth (~> 1.1, >= 1.1.1)
|
47
|
+
net-http-persistent (~> 2.5, >= 2.5.2)
|
48
|
+
nokogiri (~> 1.4)
|
49
|
+
ntlm-http (~> 0.1, >= 0.1.1)
|
50
|
+
webrobots (~> 0.0, >= 0.0.9)
|
51
|
+
method_source (0.8)
|
52
|
+
mime-types (1.19)
|
53
|
+
net-http-digest_auth (1.2.1)
|
54
|
+
net-http-persistent (2.7)
|
55
|
+
nokogiri (1.5.5)
|
56
|
+
ntlm-http (0.1.1)
|
57
|
+
pry (0.9.10)
|
58
|
+
coderay (~> 1.0.5)
|
59
|
+
method_source (~> 0.8)
|
60
|
+
slop (~> 3.3.1)
|
61
|
+
rainbow (1.1.4)
|
30
62
|
rake (0.9.2.2)
|
31
|
-
rb-appscript (0.6.1)
|
32
63
|
rb-fchange (0.0.5)
|
33
64
|
ffi
|
34
|
-
rb-fsevent (0.
|
65
|
+
rb-fsevent (0.9.1)
|
35
66
|
rb-inotify (0.8.8)
|
36
67
|
ffi (>= 0.5.0)
|
37
68
|
rcov (0.9.11)
|
@@ -44,24 +75,30 @@ GEM
|
|
44
75
|
rspec-expectations (2.7.0)
|
45
76
|
diff-lcs (~> 1.1.2)
|
46
77
|
rspec-mocks (2.7.0)
|
47
|
-
|
48
|
-
|
78
|
+
slop (3.3.3)
|
79
|
+
terminal-notifier-guard (1.5.3)
|
80
|
+
thor (0.16.0)
|
81
|
+
unf (0.0.5)
|
82
|
+
unf_ext
|
83
|
+
unf_ext (0.0.5)
|
84
|
+
webrobots (0.0.13)
|
49
85
|
|
50
86
|
PLATFORMS
|
51
87
|
ruby
|
52
88
|
|
53
89
|
DEPENDENCIES
|
90
|
+
aruba
|
54
91
|
bundler
|
55
92
|
cucumber
|
56
|
-
|
93
|
+
gli
|
57
94
|
guard
|
58
95
|
guard-cucumber
|
59
96
|
guard-rspec
|
60
97
|
jeweler (~> 1.6.4)
|
61
|
-
|
62
|
-
|
63
|
-
|
98
|
+
mechanize
|
99
|
+
pry
|
100
|
+
rainbow
|
64
101
|
rcov
|
65
102
|
rr
|
66
103
|
rspec
|
67
|
-
|
104
|
+
terminal-notifier-guard
|
data/Guardfile
CHANGED
@@ -6,11 +6,10 @@ group 'backend' do
|
|
6
6
|
watch(%r{^spec/.+_spec\.rb$})
|
7
7
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
8
8
|
|
9
|
-
# String watch patterns are matched with simple '=='
|
10
9
|
watch('spec/spec_helper.rb') { "spec" }
|
11
10
|
end
|
12
11
|
|
13
|
-
guard 'cucumber' do
|
12
|
+
guard 'cucumber', :cli => '--tags ~@slow' do
|
14
13
|
watch(%r{^features/.+\.feature$})
|
15
14
|
watch(%r{^features/support/.+$}) { 'features' }
|
16
15
|
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
data/README.md
CHANGED
@@ -1,30 +1,82 @@
|
|
1
1
|
# Klipbook
|
2
2
|
|
3
|
-
Klipbook
|
3
|
+
Klipbook collates highlights and notes that you've created on your Kindle into a nice html file.
|
4
|
+
|
5
|
+
## An example of a clippings file generated by Klipbook
|
6
|
+
|
7
|
+
<img src="https://github.com/grassdog/klipbook/raw/master/example.png" alt="Example of a clippings file" />
|
8
|
+
|
9
|
+
## What sources does it support?
|
10
|
+
|
11
|
+
Klipbook can take your highlights from a clippings file off a physical Kindle device
|
12
|
+
or from the [Kindle highlights site](https://kindle.amazon.com/your_highlights) itself.
|
13
|
+
|
14
|
+
## When should I use the file and when should I use the site?
|
15
|
+
|
16
|
+
If your books are purchased from Amazon directly then use the site. The site is the
|
17
|
+
canonical source and will contain all of your notes and highlights from across all of
|
18
|
+
your Kindle devices and applications. Currently the Amazon highlights site only shows
|
19
|
+
clippings for books you've purchased on Amazon.
|
20
|
+
|
21
|
+
If your books are personal documents and you've read them on your kindle device
|
22
|
+
itself then you should use the file from that device as a source i.e. you Kindle
|
23
|
+
device only keeps clippings that you made directly on it.
|
4
24
|
|
5
25
|
## How does it work?
|
6
26
|
|
27
|
+
Klipbook supports two main commands: `collate` and `list`.
|
28
|
+
|
29
|
+
### Collate
|
30
|
+
|
31
|
+
`collate` pulls together the clippings from your latest annotated book and combines them
|
32
|
+
into a simple html file.
|
33
|
+
|
34
|
+
#### From a file
|
35
|
+
|
7
36
|
Copy your clippings file (called "My Clippings.txt" on a 3rd generation Kindle) from your Kindle device to your local drive via USB.
|
8
37
|
|
9
|
-
|
38
|
+
Then write out a list of your clippings via:
|
10
39
|
|
11
|
-
$ klipbook
|
40
|
+
$ klipbook collate "file:My Clippings.txt"
|
12
41
|
|
13
|
-
|
14
|
-
|
15
|
-
|
42
|
+
This command will write the collected clippings for the latest annotated book to a file in the current
|
43
|
+
directory. You can override the output directory with the `--output-dir` flag.
|
44
|
+
|
45
|
+
Klipbook will not overwrite an exiting file by default. You can change this with
|
46
|
+
the `--force` flag.
|
47
|
+
|
48
|
+
You can also specify a maximum count of books you'd like collated with the `--num-books` flag.
|
49
|
+
|
50
|
+
#### From the site
|
51
|
+
|
52
|
+
Specify your amazon username and password to klipbook and it will scrape the site and
|
53
|
+
output a clippings file.
|
54
|
+
|
55
|
+
$ klipbook collate site:my-username@blah.com:my-password
|
56
|
+
|
57
|
+
The same flags above apply.
|
16
58
|
|
17
|
-
|
59
|
+
If you don't feel like having your credentials in your shell history you can set your
|
60
|
+
default source in the klipbook rc file: `~/.klipbookrc`.
|
18
61
|
|
19
|
-
|
62
|
+
This is simply a YAML file and you can specify default values for the source and the
|
63
|
+
output directory, e.g.
|
20
64
|
|
21
|
-
$
|
65
|
+
$ cat ~/.klipbookrc
|
66
|
+
source: site:my-username@blah.com:my-password
|
67
|
+
output: my/default/output/directory
|
22
68
|
|
23
|
-
|
69
|
+
Command line options override the defaults stored in the rc file.
|
24
70
|
|
25
|
-
|
71
|
+
### List
|
26
72
|
|
27
|
-
|
73
|
+
The list command lists the books avaiable in the specified source.
|
74
|
+
|
75
|
+
$ klipbook list file:"My Clippings.txt"
|
76
|
+
|
77
|
+
Book list:
|
78
|
+
[1] The Big Sleep by Raymond Chandler
|
79
|
+
[2] How to jump out of a plane without a parachute and survive by Rip Rockjaw
|
28
80
|
|
29
81
|
## Installation
|
30
82
|
|
@@ -32,17 +84,13 @@ Klipbook is a Ruby gem. To install simply run:
|
|
32
84
|
|
33
85
|
gem install klipbook
|
34
86
|
|
35
|
-
## Why not just see your clippings on the Amazon site?
|
36
|
-
|
37
|
-
Currently [the Amazon highlights site](https://kindle.amazon.com/your_highlights) only shows clippings for books you've purchased on Amazon.
|
38
|
-
|
39
87
|
## Supported Devices
|
40
88
|
|
41
89
|
Klipbook has been tested on clippings files from 3rd generation Kindles and the Kindle Touch.
|
42
90
|
|
43
91
|
## Tested platforms
|
44
92
|
|
45
|
-
Klipbook has been tested on Mac OSX Lion
|
93
|
+
Klipbook has been tested on Mac OSX Mountain Lion using MRI 1.9.3.
|
46
94
|
|
47
95
|
## Contributing to Klipbook
|
48
96
|
|
@@ -50,5 +98,5 @@ Fork the project on [Github](https://github.com/grassdog/klipbook), add tests fo
|
|
50
98
|
|
51
99
|
## Copyright
|
52
100
|
|
53
|
-
Copyright (c)
|
101
|
+
Copyright (c) 2012 Ray Grasso. See LICENSE.txt for further details.
|
54
102
|
|
data/Rakefile
CHANGED
@@ -42,7 +42,11 @@ RSpec::Core::RakeTask.new(:spec)
|
|
42
42
|
|
43
43
|
require 'cucumber/rake/task'
|
44
44
|
Cucumber::Rake::Task.new(:features) do |t|
|
45
|
-
t.cucumber_opts = '--format
|
45
|
+
t.cucumber_opts = '--format pretty --tags ~@slow'
|
46
|
+
end
|
47
|
+
|
48
|
+
Cucumber::Rake::Task.new(:allfeatures) do |t|
|
49
|
+
t.cucumber_opts = '--format pretty'
|
46
50
|
end
|
47
51
|
|
48
52
|
desc 'Default: run specs'
|
data/bin/klipbook
CHANGED
@@ -1,7 +1,91 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
$LOAD_PATH << File.expand_path('../../lib', __FILE__)
|
4
|
+
|
5
|
+
require 'gli'
|
4
6
|
require 'klipbook'
|
5
7
|
|
6
|
-
|
8
|
+
include GLI::App
|
9
|
+
|
10
|
+
program_desc "Collates the clippings you've saved on your Kindle into a nice html summary for each book."
|
11
|
+
|
12
|
+
SOURCE_HELP = "Two sources are currently supported: a file from a Kindle device and the Kindle site itself.\n\n" +
|
13
|
+
"Example file formats:\n\n" +
|
14
|
+
" file:path/to/my-clippings-file.txt\n\n" +
|
15
|
+
" site:my-kindle-user@blah.com:my-kindle-password\n\n" +
|
16
|
+
"Note that source and output file defaults can be stored in a file called ~/.klipbookrc\n\n" +
|
17
|
+
"This file is YAML formatted e.g.\n\n" +
|
18
|
+
"source: site:my-kindle-user@blah.com:my-kindle-password\n\n" +
|
19
|
+
"output: my/default/output/directory"
|
20
|
+
|
21
|
+
version Klipbook::VERSION
|
22
|
+
|
23
|
+
desc 'Number of books to process'
|
24
|
+
arg_name 'count'
|
25
|
+
default_value 1
|
26
|
+
flag [:n, :'num-books']
|
27
|
+
|
28
|
+
desc 'Collate your clippings into a html file for each book'
|
29
|
+
arg_name 'source'
|
30
|
+
long_desc "Clippings are fetched from the specified source before being collated into html " +
|
31
|
+
"files and written into the current directory.\n\n" + SOURCE_HELP
|
32
|
+
command :collate do |c|
|
33
|
+
|
34
|
+
c.desc 'Override the directory path where collated files are written'
|
35
|
+
c.arg_name 'Directory'
|
36
|
+
c.flag [:o, :'output-dir']
|
37
|
+
|
38
|
+
c.desc 'Force overwrite of any existing collated files'
|
39
|
+
c.switch [:f, :force]
|
40
|
+
|
41
|
+
c.action do |globals,options,args|
|
42
|
+
books = fetch_books(args, globals)
|
43
|
+
Klipbook::Collator.new(books).collate_books(output_dir(options), options[:f])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
desc 'List available books'
|
48
|
+
arg_name 'source'
|
49
|
+
long_desc "Clippings are fetched from the specified source before being listed to screen.\n\n" + SOURCE_HELP
|
50
|
+
command :list do |c|
|
51
|
+
c.action do |globals,options,args|
|
52
|
+
books = fetch_books(args, globals)
|
53
|
+
Klipbook::Printer.new(books).print
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
pre do |globals,command,options,args|
|
58
|
+
unless source_spec(args)
|
59
|
+
raise InvalidSourceError
|
60
|
+
end
|
61
|
+
|
62
|
+
odir = output_dir(options)
|
63
|
+
if odir && !File.exists?(odir)
|
64
|
+
raise "Output directory doesn't exist: #{odir}"
|
65
|
+
end
|
66
|
+
|
67
|
+
if globals[:n].to_i == 0
|
68
|
+
raise 'Specify a number of books greater than 0'
|
69
|
+
end
|
70
|
+
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
def source_spec(args)
|
75
|
+
@source_spec ||= (args[0] || Klipbook::Config.new.read[:source])
|
76
|
+
end
|
77
|
+
|
78
|
+
def fetch_books(args, globals)
|
79
|
+
Klipbook::Fetcher.new(source_spec(args), globals[:n].to_i).fetch_books
|
80
|
+
end
|
81
|
+
|
82
|
+
def output_dir(options)
|
83
|
+
@output_dir ||= unless options[:o] == 'Current directory'
|
84
|
+
options[:o]
|
85
|
+
else
|
86
|
+
Klipbook::Config.new.read[:output] || Dir.pwd
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
exit run(ARGV)
|
7
91
|
|
data/example.png
CHANGED
Binary file
|
@@ -0,0 +1,51 @@
|
|
1
|
+
Feature: klipbook collates the clippings from a clippings file
|
2
|
+
As an avid reader and note taker
|
3
|
+
I want to see a pretty html collation for books that I've read
|
4
|
+
So that I can refer to a nice summary of passages I enjoyed in the book
|
5
|
+
|
6
|
+
Scenario: File with clippings for a book
|
7
|
+
Given a directory named "output"
|
8
|
+
And a file that contains clippings for 3 books called "input.txt"
|
9
|
+
When I collate clippings for "3" books from the file "input.txt" to the output directory "output"
|
10
|
+
Then I should find a file in the folder "output" named "Lean Software Development: An Agile Toolkit by Mary Poppendieck and Tom Poppendieck.html" that contains "13" clippings
|
11
|
+
Then I should find a file in the folder "output" named "Instapaper: Long Reads by Instapaper: Long Reads.html" that contains "4" clippings
|
12
|
+
Then I should find a file in the folder "output" named "Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin.html" that contains "3" clippings
|
13
|
+
And the exit status should be 0
|
14
|
+
|
15
|
+
Scenario: Attempting to write to an existing file
|
16
|
+
Given a directory named "output"
|
17
|
+
And a file in "output" named "Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin.html"
|
18
|
+
And a file that contains clippings for 3 books called "input.txt"
|
19
|
+
When I collate clippings for "3" books from the file "input.txt" to the output directory "output"
|
20
|
+
Then the output should contain "Skipping Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin.html"
|
21
|
+
And the exit status should be 0
|
22
|
+
|
23
|
+
Scenario: Force overwrite of an existing file
|
24
|
+
Given a directory named "output"
|
25
|
+
And a file in "output" named "Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin.html"
|
26
|
+
And a file that contains clippings for 3 books called "input.txt"
|
27
|
+
When I collate clippings for "3" books from the file "input.txt" to the output directory "output" forcefully
|
28
|
+
Then the output should contain "Writing Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin.html"
|
29
|
+
And the exit status should be 0
|
30
|
+
|
31
|
+
Scenario: Attempt to write with a bad number of books
|
32
|
+
Given a directory named "output"
|
33
|
+
And a file that contains clippings for 3 books called "input.txt"
|
34
|
+
When I collate clippings for "notanumber" books from the file "input.txt" to the output directory "output"
|
35
|
+
Then the output should contain "error: Specify a number of books greater than 0"
|
36
|
+
And the exit status should be 1
|
37
|
+
|
38
|
+
Scenario: Attempt to write to a non-existent directory
|
39
|
+
Given there is not a directory named "output"
|
40
|
+
And a file that contains clippings for 3 books called "input.txt"
|
41
|
+
When I collate clippings for "3" books from the file "input.txt" to the output directory "output"
|
42
|
+
Then the output should contain "error: Output directory doesn't exist: output"
|
43
|
+
And the exit status should be 1
|
44
|
+
|
45
|
+
@slow
|
46
|
+
Scenario: Site with clippings for a book
|
47
|
+
Given a directory named "output"
|
48
|
+
When I collate clippings for "1" books from the kindle site to the output directory "output"
|
49
|
+
Then I should find "1" collated files containing clippings in the directory "output"
|
50
|
+
And the exit status should be 0
|
51
|
+
|
@@ -0,0 +1,105 @@
|
|
1
|
+
Clean Code: A Handbook of Agile Software Craftsmanship (Robert C. Martin)
|
2
|
+
- Highlight Loc. 4536-37 | Added on Tuesday, August 21, 2012, 09:32 PM
|
3
|
+
|
4
|
+
Concurrency can sometimes improve performance, but only when there is a lot of wait time that can be shared between multiple threads or multiple processors. Neither situation is trivial.
|
5
|
+
==========
|
6
|
+
Clean Code: A Handbook of Agile Software Craftsmanship (Robert C. Martin)
|
7
|
+
- Note Loc. 4713 | Added on Tuesday, August 21, 2012, 09:43 PM
|
8
|
+
|
9
|
+
Recommendations for developing concurrent systems
|
10
|
+
==========
|
11
|
+
Clean Code: A Handbook of Agile Software Craftsmanship (Robert C. Martin)
|
12
|
+
- Highlight Loc. 4745-46 | Added on Tuesday, August 21, 2012, 09:45 PM
|
13
|
+
|
14
|
+
Things happen when the system switches between tasks. To encourage task swapping, run with more threads than processors or cores. The more frequently your tasks swap, the more likely you’ll encounter code that is missing a critical section or causes deadlock.
|
15
|
+
==========
|
16
|
+
Instapaper: Long Reads (Instapaper: Long Reads)
|
17
|
+
- Highlight Loc. 91-93 | Added on Sunday, April 24, 2011, 02:20 PM
|
18
|
+
|
19
|
+
3. Do not freeze work design into code! Leave as much work design as possible for work teams to determine and modify. If that is not possible, make sure that the people who will live with the new system are involved in the design of their work.
|
20
|
+
==========
|
21
|
+
Instapaper: Long Reads (Instapaper: Long Reads)
|
22
|
+
- Highlight Loc. 90-91 | Added on Sunday, April 24, 2011, 02:20 PM
|
23
|
+
|
24
|
+
2. Simplify before you automate. Never automate a work process until the work teams have devised as simple a work process as they possibly can. Automating the right thing is at least as important as automating it right.
|
25
|
+
==========
|
26
|
+
Instapaper: Long Reads (Instapaper: Long Reads)
|
27
|
+
- Highlight Loc. 150-51 | Added on Sunday, April 24, 2011, 02:25 PM
|
28
|
+
|
29
|
+
Roll-in of progressive change They started off with small teams (4 people in the beginning) so not a big bang approach.
|
30
|
+
==========
|
31
|
+
Instapaper: Long Reads (Instapaper: Long Reads)
|
32
|
+
- Highlight Loc. 167-72 | Added on Sunday, April 24, 2011, 02:28 PM
|
33
|
+
|
34
|
+
What is management’s role? The hardest part is working with managers and helping them see their new role. Their role becomes understanding demand, thinking outside in, engage staff, walk the process, allow staff to experiment with design and evaluate etc. Previously managers used to be specialists at solving tricky decisions, but now they have to become a specialist in training (moving from ‘disablers’ to ‘enablers). They now need to create conditions that enable workers to reach their goals. They need to support and encourage the initiative of the workers. They need to ensure that the process / initiative is end to end. Also, building agreement with others outside the process.
|
35
|
+
==========
|
36
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
37
|
+
- Highlight Loc. 921-23 | Added on Monday, April 25, 2011, 09:18 AM
|
38
|
+
|
39
|
+
Your objective should be to balance experimentation with deliberation and review. In order to do this, consider how you can generate the most knowledge at the least cost in your circumstances.
|
40
|
+
==========
|
41
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
42
|
+
- Highlight Loc. 930-32 | Added on Monday, April 25, 2011, 01:10 PM
|
43
|
+
|
44
|
+
There are many ways to represent the system, from models to prototypes, to incremental deliveries, but the important thing is to select the representation that gathers the most knowledge. Most users relate better to seeing working screens than to a requirements document, so working software tends to generate better knowledge faster.
|
45
|
+
==========
|
46
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
47
|
+
- Highlight Loc. 1035-44 | Added on Monday, April 25, 2011, 01:21 PM
|
48
|
+
|
49
|
+
In most cases, increasing feedback, not decreasing it, is the single most effective way to deal with troubled software development projects and environments. Instead of letting defects accumulate, run tests as soon as the code is written. Instead of adding more documentation or detailed planning, try checking out ideas by writing code. Instead of gathering more requirements from users, show them an assortment of potential user screens and get their input. Instead of studying more carefully which tool to use, bring the top three candidates inhouse and test them. Instead of trying to figure out how to convert an entire system in a single massive effort, create a Web front end to the legacy system and try the new idea out.
|
50
|
+
==========
|
51
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
52
|
+
- Highlight Loc. 1066-67 | Added on Monday, April 25, 2011, 01:24 PM
|
53
|
+
|
54
|
+
One reason just-in-time flow is so effective is that it requires significantly improved worker-to-worker communication and surfaces quality problems as soon as they occur.
|
55
|
+
==========
|
56
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
57
|
+
- Highlight Loc. 1074-77 | Added on Monday, April 25, 2011, 01:28 PM
|
58
|
+
|
59
|
+
An iteration is a useful increment of software that is designed, programmed, tested, integrated, and delivered during a short, fixed timeframe. It is very similar to a prototype in product development except that an iteration produces a working portion of the final product. This software will be improved in future iterations, but it is working, tested, integrated code from the beginning.
|
60
|
+
==========
|
61
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
62
|
+
- Highlight Loc. 1180-81 | Added on Monday, April 25, 2011, 02:34 PM
|
63
|
+
|
64
|
+
A Standish Group study found that 45 percent of features in a typical system are never used and 19 percent are rarely used.
|
65
|
+
==========
|
66
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
67
|
+
- Highlight Loc. 1359-62 | Added on Tuesday, April 26, 2011, 08:34 AM
|
68
|
+
|
69
|
+
When you have a difficult problem, try this: Develop a set of alternative solutions to a problem, see how well they actually work, and then merge the best features of the solutions or choose one of the alternatives. It might seem wasteful to develop multiple solutions to the same problem, but set-based development can lead to better solutions faster,
|
70
|
+
==========
|
71
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
72
|
+
- Bookmark Loc. 1364 | Added on Tuesday, April 26, 2011, 08:36 AM
|
73
|
+
|
74
|
+
|
75
|
+
==========
|
76
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
77
|
+
- Highlight Loc. 1392-93 | Added on Tuesday, April 26, 2011, 08:42 AM
|
78
|
+
|
79
|
+
Set-based development means that you communicate constraints, not solutions.
|
80
|
+
==========
|
81
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
82
|
+
- Highlight Loc. 1535-36 | Added on Tuesday, April 26, 2011, 08:59 AM
|
83
|
+
|
84
|
+
This presents us with a new category of waste: waste caused by software that is difficult to change.
|
85
|
+
==========
|
86
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
87
|
+
- Highlight Loc. 1586-88 | Added on Tuesday, April 26, 2011, 09:10 AM
|
88
|
+
|
89
|
+
Lean software development emphasizes developing a robust, change-tolerant design, one that accepts the inevitability of change and structures the system so that it can be readily adapted to the most likely kinds of changes.
|
90
|
+
==========
|
91
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
92
|
+
- Highlight Loc. 1588-89 | Added on Tuesday, April 26, 2011, 09:11 AM
|
93
|
+
|
94
|
+
The main reason software changes throughout its lifecycle is that the business process in which it is used evolves over time.
|
95
|
+
==========
|
96
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
97
|
+
- Highlight Loc. 1627-28 | Added on Tuesday, April 26, 2011, 09:19 AM
|
98
|
+
|
99
|
+
the underlying economic mechanism for controlling complexity in just-in-time systems is minimizing irreversible actions.
|
100
|
+
==========
|
101
|
+
Lean Software Development: An Agile Toolkit (Mary Poppendieck and Tom Poppendieck)
|
102
|
+
- Highlight Loc. 1722-23 | Added on Tuesday, April 26, 2011, 09:48 AM
|
103
|
+
|
104
|
+
Good design is a discovery process, done through short, repeated exploratory cycles.
|
105
|
+
==========
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Feature: klipbook lists the books in a clipping file
|
2
|
+
As an avid reader and note taker
|
3
|
+
I want to be shown an indexed list of books
|
4
|
+
So that I can see which books are available for collation
|
5
|
+
|
6
|
+
Scenario: Empty file
|
7
|
+
Given I have a clippings file "input.txt" that contains no clippings
|
8
|
+
When I list "1" books in the file "input.txt"
|
9
|
+
Then the output should contain "No books available"
|
10
|
+
And the exit status should be 0
|
11
|
+
|
12
|
+
Scenario: File with one book
|
13
|
+
Given a file that contains clippings for 3 books called "input.txt"
|
14
|
+
When I list "5" books in the file "input.txt"
|
15
|
+
Then the output should contain "[1] Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin"
|
16
|
+
Then the output should contain "[2] Lean Software Development: An Agile Toolkit by Mary Poppendieck and Tom Poppendieck"
|
17
|
+
Then the output should contain "[3] Instapaper: Long Reads by Instapaper: Long Reads"
|
18
|
+
And the exit status should be 0
|
19
|
+
|
20
|
+
Scenario: File with one book
|
21
|
+
Given a file that contains clippings for 3 books called "input.txt"
|
22
|
+
When I list "5" books in the file "input.txt"
|
23
|
+
Then the output should match /\[1\] .+ by .+/
|
24
|
+
And the exit status should be 0
|
25
|
+
|
26
|
+
@slow
|
27
|
+
Scenario: Site with one book
|
28
|
+
When I list "1" books from the kindle site
|
29
|
+
Then the output should match /\[1\] .+ by .+/
|
30
|
+
And the exit status should be 0
|
31
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
CLIPPING_FILE = File.join(File.dirname(__FILE__), '../fixtures/clippings-for-three-books.txt')
|
2
|
+
|
3
|
+
Given /^a file in "([^"]*)" named "([^"]*)"$/ do |output_dir, file_name|
|
4
|
+
in_current_dir { FileUtils.touch(File.join(output_dir, file_name)) }
|
5
|
+
end
|
6
|
+
|
7
|
+
Given /^there is not a directory named "([^"]*)"$/ do |directory_name|
|
8
|
+
in_current_dir do
|
9
|
+
FileUtils.rm_f(directory_name)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Given /^a file that contains clippings for 3 books called "([^"]*)"$/ do |file_name|
|
14
|
+
in_current_dir { FileUtils.cp(CLIPPING_FILE, file_name) }
|
15
|
+
end
|
16
|
+
|
17
|
+
When /^I collate clippings for "([^"]*)" books from the file "([^"]*)" to the output directory "([^"]*)"$/ do |book_count, input_file, output_dir|
|
18
|
+
run_collate_file(book_count, output_dir, input_file, false)
|
19
|
+
end
|
20
|
+
|
21
|
+
When /^I collate clippings for "([^"]*)" books from the file "([^"]*)" to the output directory "([^"]*)" forcefully$/ do |book_count, input_file, output_dir|
|
22
|
+
run_collate_file(book_count, output_dir, input_file, true)
|
23
|
+
end
|
24
|
+
|
25
|
+
Then /^I should find a file in the folder "([^"]*)" named "([^"]*)" that contains "([^"]*)" clippings$/ do |output_folder, file_name, clipping_count|
|
26
|
+
in_current_dir do
|
27
|
+
file_path = File.join(output_folder, file_name)
|
28
|
+
File.exists?(file_path).should be_true
|
29
|
+
File.open(file_path, 'r') do |f|
|
30
|
+
f.read.should match(/<footer>\s+#{clipping_count} clippings •/m)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# FIXME This step currently assumes you have site: set up in your klipbookrc
|
36
|
+
When /^I collate clippings for "([^"]*)" books from the kindle site to the output directory "([^"]*)"$/ do |book_count, output_dir|
|
37
|
+
run_simple(unescape("klipbook -n #{book_count} collate -o #{output_dir}"), false)
|
38
|
+
end
|
39
|
+
|
40
|
+
Then /^I should find "([^"]*)" collated files containing clippings in the directory "([^"]*)"$/ do |file_count, output_dir|
|
41
|
+
in_current_dir do
|
42
|
+
files = Dir['output/*.html']
|
43
|
+
files.should have(file_count.to_i).items
|
44
|
+
files.each do |fname|
|
45
|
+
File.open(fname, 'r') do |f|
|
46
|
+
f.read.should match(/<footer>\s+\d+ clippings •/m)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def run_collate_file(book_count, output, input, force=false)
|
53
|
+
force_str = if force
|
54
|
+
'-f'
|
55
|
+
else
|
56
|
+
''
|
57
|
+
end
|
58
|
+
|
59
|
+
run_simple(unescape("klipbook -n #{book_count} collate #{force_str} -o #{output} file:#{input}"), false)
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
Given /^I have a clippings file "([^"]*)" that contains no clippings$/ do |input_file|
|
3
|
+
in_current_dir do
|
4
|
+
FileUtils.touch(input_file)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
When /^I list "([^"]*)" books in the file "([^"]*)"$/ do |book_count, input_file|
|
9
|
+
run_simple(unescape("klipbook -n #{book_count} list file:#{input_file}"), false)
|
10
|
+
end
|
11
|
+
|
12
|
+
# FIXME This step currently assumes you have site: set up in your klipbookrc
|
13
|
+
When /^I list "([^"]*)" books from the kindle site$/ do |book_count|
|
14
|
+
run_simple(unescape("klipbook -n #{book_count} list"), false)
|
15
|
+
end
|