insta_readability 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.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'readit',:git=>'git@github.com:29decibel/readit.git'
4
+ gem 'highline'
5
+
6
+ gem 'rspec'
7
+ gem 'mechanize'
8
+ gem 'bourne'
9
+ gem 'mocha'
10
+ gem 'vcr'
@@ -0,0 +1,62 @@
1
+ GIT
2
+ remote: git@github.com:29decibel/readit.git
3
+ revision: 05446d377d3328f801fe5f7830b952e6acf7d2c6
4
+ specs:
5
+ readit (0.0.9)
6
+ hashie
7
+ multi_json
8
+ oauth
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ bourne (1.4.0)
14
+ mocha (~> 0.13.2)
15
+ diff-lcs (1.2.4)
16
+ domain_name (0.5.11)
17
+ unf (>= 0.0.5, < 1.0.0)
18
+ hashie (2.0.4)
19
+ highline (1.6.12)
20
+ mechanize (2.6.0)
21
+ domain_name (~> 0.5, >= 0.5.1)
22
+ mime-types (~> 1.17, >= 1.17.2)
23
+ net-http-digest_auth (~> 1.1, >= 1.1.1)
24
+ net-http-persistent (~> 2.5, >= 2.5.2)
25
+ nokogiri (~> 1.4)
26
+ ntlm-http (~> 0.1, >= 0.1.1)
27
+ webrobots (>= 0.0.9, < 0.2)
28
+ metaclass (0.0.1)
29
+ mime-types (1.23)
30
+ mocha (0.13.3)
31
+ metaclass (~> 0.0.1)
32
+ multi_json (1.7.2)
33
+ net-http-digest_auth (1.3)
34
+ net-http-persistent (2.8)
35
+ nokogiri (1.5.9)
36
+ ntlm-http (0.1.1)
37
+ oauth (0.4.7)
38
+ rspec (2.13.0)
39
+ rspec-core (~> 2.13.0)
40
+ rspec-expectations (~> 2.13.0)
41
+ rspec-mocks (~> 2.13.0)
42
+ rspec-core (2.13.1)
43
+ rspec-expectations (2.13.0)
44
+ diff-lcs (>= 1.1.3, < 2.0)
45
+ rspec-mocks (2.13.1)
46
+ unf (0.1.1)
47
+ unf_ext
48
+ unf_ext (0.0.6)
49
+ vcr (2.4.0)
50
+ webrobots (0.1.1)
51
+
52
+ PLATFORMS
53
+ ruby
54
+
55
+ DEPENDENCIES
56
+ bourne
57
+ highline
58
+ mechanize
59
+ mocha
60
+ readit!
61
+ rspec
62
+ vcr
@@ -0,0 +1,34 @@
1
+ InstaReadability
2
+ =================
3
+
4
+ Uploads bookmarks to Readability.com from an Instapaper CSV export
5
+
6
+ Installation
7
+ ---
8
+
9
+ `gem install insta_readability`
10
+
11
+
12
+ Dependancies
13
+ ---
14
+ You will need to have a Readability Key and Secret in a file as follows:
15
+
16
+ ```
17
+ # ~/.insta_readability.rb
18
+
19
+ Readit::Config.consumer_key = 'somename'
20
+ Readit::Config.consumer_secret = 'someSHA'
21
+
22
+ ```
23
+
24
+ You can generate your key and secret at http://www.readability.com/account/api
25
+ It will be under the _Reader API Key_ section.
26
+
27
+ Usage
28
+ ---
29
+
30
+ run the following and enter your username and password when prompter:
31
+
32
+ ```
33
+ insta_readability csv_file
34
+ ```
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'insta_readability'
3
+
4
+ InstaReadability::CLI.run ARGV[0]
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'insta_readability/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'insta_readability'
7
+ s.version = InstaReadability::VERSION
8
+ s.summary = "InstaReadability"
9
+ s.description = "Upload exported Instapaper csv to Readability.com"
10
+ s.authors = ["Will Mernagh"]
11
+ s.email = 'wmernagh@gmail.com'
12
+ s.homepage = 'https://github.com/wmernagh/insta_readability'
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+ end
@@ -0,0 +1,6 @@
1
+ require 'insta_readability/bookmark'
2
+ require 'insta_readability/importer'
3
+ require 'insta_readability/cli'
4
+
5
+ module InstaReadability
6
+ end
@@ -0,0 +1,22 @@
1
+ require 'highline/import'
2
+ require 'oauth'
3
+ require 'readit'
4
+ require '~/.insta_readability'
5
+
6
+ module InstaReadability
7
+ class Auth
8
+ def self.get_access_token
9
+ uname = highline.ask ("Username: ")
10
+ passwd = highline.ask ("Password: ") {|q| q.echo = false}
11
+
12
+ consumer = ::OAuth::Consumer.new(Readit::Config.consumer_key, Readit::Config.consumer_secret, :site=>"https://www.readability.com/", :access_token_path => "/api/rest/v1/oauth/access_token/")
13
+ consumer.get_access_token(nil, {}, {:x_auth_mode => 'client_auth', :x_auth_username => uname, :x_auth_password => passwd})
14
+ end
15
+
16
+ private
17
+
18
+ def self.highline
19
+ HighLine.new
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module InstaReadability
2
+ class Bookmark
3
+ ATTRIBUTES = [:url, :favorite, :archive, :allow_duplicates]
4
+ attr_reader *ATTRIBUTES
5
+
6
+ def initialize(options={})
7
+ @archive, @favorite, @allow_duplicates = 0, 0, 0
8
+ options.each_pair { |attr, value| instance_variable_set("@#{attr}", value) }
9
+ end
10
+
11
+ def ==(o)
12
+ o.class == self.class && o.to_hash == to_hash
13
+ end
14
+ alias_method :eql?, :==
15
+
16
+ def to_hash
17
+ ATTRIBUTES.inject({}) do |hash, attribute|
18
+ hash[attribute] = self.send attribute.to_s
19
+ hash
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ require 'readit'
2
+ require 'singleton'
3
+ require 'insta_readability/auth'
4
+ require 'insta_readability/instapaper_parser'
5
+
6
+ module InstaReadability
7
+ class CLI
8
+ include Singleton
9
+ USAGE_MESSAGE = "Usage: $0 PATH_TO_CSV_FILE"
10
+ attr_reader :auth
11
+
12
+ def initialize
13
+ @auth = Auth.get_access_token
14
+ end
15
+
16
+ def self.run(csv_path='')
17
+ if csv_path == ''
18
+ $stderr.print USAGE_MESSAGE
19
+ return
20
+ end
21
+
22
+ parser = InstaReadability::InstapaperParser.new csv_path
23
+ importer = InstaReadability::Importer.new(instance.auth.token, instance.auth.secret)
24
+ importer.import parser.create_bookmarks
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ require 'logger'
2
+ module InstaReadability
3
+ class Importer
4
+ def initialize(token, secret, logger=::Logger.new($stderr))
5
+ @logger = logger
6
+ @api = Readit::API.new token, secret
7
+ end
8
+
9
+ def import(bookmarks)
10
+ bookmarks.each do |bm|
11
+ status = save bm
12
+ update status['bookmark_id'], bm if status['status'] == '409'
13
+ @logger.info status
14
+ end
15
+ end
16
+
17
+ def save(bookmark)
18
+ @api.bookmark bookmark.to_hash
19
+ end
20
+
21
+ def update(id, bookmark)
22
+ @api.update_bookmark id, bookmark.to_hash
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ require 'csv'
2
+
3
+ module InstaReadability
4
+ class InstapaperParser
5
+ def initialize(csv_path)
6
+ @csv_path = csv_path
7
+ end
8
+
9
+ def create_bookmarks
10
+ bookmarks = []
11
+
12
+ CSV.foreach(@csv_path, headers: true) do |row|
13
+ bookmark = Bookmark.new ({
14
+ url: row['URL'],
15
+ favorite: row['Folder'] == 'Starred',
16
+ archive: row['Folder'] == 'Archive'
17
+ })
18
+ bookmarks << bookmark
19
+ end
20
+
21
+ bookmarks
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module InstaReadability
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'highline/import'
3
+
4
+ describe InstaReadability::Auth do
5
+ let(:consumer) { stub(:get_access_token) }
6
+
7
+ before do
8
+ @old_stdout = $stdout
9
+ @old_stdin = $stdin
10
+ $stdin = StringIO.new
11
+ $stdout = StringIO.new
12
+ @terminal = ::HighLine.new($stdin, $stdout)
13
+ HighLine.stubs(:new).returns @terminal
14
+ @terminal.stubs(:ask).with('Username: ').returns 'wmernagh'
15
+ @terminal.stubs(:ask).with('Password: ').returns 'my-password'
16
+ OAuth::Consumer.stubs(:new).with(Readit::Config.consumer_key, Readit::Config.consumer_secret, :site=>"https://www.readability.com/", :access_token_path => "/api/rest/v1/oauth/access_token/").returns consumer
17
+ end
18
+
19
+ after do
20
+ $stdin = @old_stdin
21
+ $stdout = @old_stdout
22
+ end
23
+
24
+ describe '.get_access_token' do
25
+ it 'prompts the user for their username' do
26
+ InstaReadability::Auth.get_access_token
27
+ expect(@terminal).to have_received(:ask).with "Username: "
28
+ end
29
+
30
+ it 'prompts the user for their password' do
31
+ InstaReadability::Auth.get_access_token
32
+ expect(@terminal).to have_received(:ask).with "Password: "
33
+ end
34
+
35
+ it 'returns the authenticated Readability token' do
36
+ consumer.stubs(:get_access_token).with(nil, {}, {:x_auth_mode => 'client_auth', :x_auth_username => 'wmernagh', :x_auth_password => 'my-password'}).returns 'token'
37
+ expect(InstaReadability::Auth.get_access_token).to eq 'token'
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe InstaReadability::Bookmark do
4
+ describe 'new' do
5
+ context 'default bookmark' do
6
+ subject(:bookmark) { InstaReadability::Bookmark.new }
7
+
8
+ it 'sets default parameters to false' do
9
+ expect(bookmark.favorite).to be 0
10
+ expect(bookmark.archive).to be 0
11
+ expect(bookmark.allow_duplicates).to be 0
12
+ end
13
+ end
14
+
15
+ context 'custom bookmark' do
16
+ subject(:bookmark) do
17
+ InstaReadability::Bookmark.new url: 'url', favorite: true, archive: true
18
+ end
19
+
20
+ it 'assigns passed in parameters' do
21
+ expect(bookmark.favorite).to be true
22
+ expect(bookmark.archive).to be true
23
+ expect(bookmark.url).to eq 'url'
24
+ end
25
+ end
26
+ end
27
+
28
+ describe '==' do
29
+ let(:source) { InstaReadability::Bookmark.new(url: 1, favorite: 2, archive: 3) }
30
+
31
+ context 'all attributes are equal' do
32
+ let(:bookmark) { InstaReadability::Bookmark.new(url: 1, favorite: 2, archive: 3) }
33
+
34
+ it 'is returns true' do
35
+ expect(source == bookmark).to be true
36
+ end
37
+ end
38
+
39
+ context 'an attribute is different' do
40
+ let(:bookmark) { InstaReadability::Bookmark.new(url: 4, favorite: 2, archive: 3) }
41
+
42
+ it 'returns false' do
43
+ expect(source == bookmark).to be false
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '#to_hash' do
49
+ let(:bookmark) { InstaReadability::Bookmark.new(url: 1, favorite: 2, archive: 3) }
50
+
51
+ it 'returns a hash of instance variables' do
52
+ expect(bookmark.to_hash).to eq({ url: 1, favorite: 2, archive: 3, :allow_duplicates=>0 })
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe InstaReadability::CLI, '.run' do
4
+ let(:access_token) { OpenStruct.new(token: 'token', secret: 'secret') }
5
+ subject(:cli) { InstaReadability::CLI }
6
+
7
+ before do
8
+ @old_stderr = $stderr
9
+ $stderr = StringIO.new
10
+ InstaReadability::Auth.stubs(:get_access_token).returns access_token
11
+ end
12
+
13
+ after do
14
+ $stderr = @old_stderr
15
+ end
16
+
17
+ context 'incorrect args' do
18
+ it 'does not authenticates the user' do
19
+ expect(InstaReadability::Auth).to have_received(:get_access_token).never
20
+ end
21
+
22
+ it 'returns without an import attempt' do
23
+ importer = mock
24
+ InstaReadability::Importer.stubs(:new).returns importer
25
+
26
+ cli.run
27
+
28
+ expect(importer).to have_received(:import).never
29
+ end
30
+
31
+ it 'prints out the usage instructions' do
32
+ $stderr.stubs(:print)
33
+ usage_message = "Usage: $0 PATH_TO_CSV_FILE"
34
+
35
+ cli.run
36
+
37
+ expect($stderr).to have_received(:print).with usage_message
38
+ end
39
+ end
40
+
41
+ context 'correct args' do
42
+ let(:importer) { mock(:import) }
43
+ let(:bookmarks) { mock }
44
+ let(:parser) { mock(create_bookmarks: bookmarks) }
45
+
46
+ before do
47
+ csv_path = 'path to csv file'
48
+ InstaReadability::InstapaperParser.stubs(:new).with(csv_path).returns parser
49
+ InstaReadability::Importer.stubs(:new).with(access_token.token, access_token.secret).returns importer
50
+ cli.run csv_path
51
+ end
52
+
53
+ it 'authenticates the user' do
54
+ expect(InstaReadability::Auth).to have_received(:get_access_token)
55
+ end
56
+
57
+ it 'imports the bookmarks' do
58
+ expect(importer).to have_received(:import).with bookmarks
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe InstaReadability::Importer do
4
+ let(:token) { 'access token' }
5
+ let(:secret) { 'access token secret' }
6
+ let(:api) { mock }
7
+ let(:logger) { mock }
8
+
9
+ subject(:importer) { InstaReadability::Importer.new token, secret, logger }
10
+
11
+ before do
12
+ Readit::API.stubs(:new).with(token, secret).returns api
13
+ end
14
+
15
+ describe 'initialize' do
16
+ it 'sets a readit api instance' do
17
+ expect(importer.instance_variable_get(:@api)).to be api
18
+ end
19
+ end
20
+
21
+ describe '#import' do
22
+ let(:bookmarks) { [1, 2, 3] }
23
+ let(:status) { {:status => '202',:bookmark_id => '233444', :article_id => 't323r2'} }
24
+
25
+ before do
26
+ logger.stubs(:info)
27
+ importer.stubs(:save).returns(status)
28
+ importer.import bookmarks
29
+ end
30
+
31
+ it 'imports each bookmark' do
32
+ bookmarks.each do |bookmark|
33
+ expect(importer).to have_received(:save).with bookmark
34
+ end
35
+ end
36
+
37
+ it 'logs the result of the import' do
38
+ expect(logger).to have_received(:info).with(status).times(3)
39
+ end
40
+ end
41
+
42
+ describe '#save!' do
43
+ let(:bookmark) { InstaReadability::Bookmark.new(url: 4, favorite: 2, archive: 3) }
44
+
45
+ it 'creates a bookmark at Readability' do
46
+ api.stubs(:bookmark)
47
+
48
+ importer.save(bookmark)
49
+
50
+ expect(api).to have_received(:bookmark).with(bookmark.to_hash)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe InstaReadability::InstapaperParser do
4
+ let(:csv) { '/path/to/file' }
5
+
6
+ let(:rows) do
7
+ [
8
+ {
9
+ 'URL' => 'http://t.co/4MPuTK9dXn',
10
+ 'Title' => 'A silly title',
11
+ 'Selection' => 'No one cares',
12
+ 'Folder' => 'Archive',
13
+ },
14
+ {
15
+ 'URL' => 'http://t.co/guSIBHxBaV',
16
+ 'Title' => 'Some silly title',
17
+ 'Selection' => 'Who cares',
18
+ 'Folder' => 'Starred',
19
+ },
20
+ {
21
+ 'URL' => 'http://t.co/9FDQCZLDQm',
22
+ 'Title' => 'Another title',
23
+ 'Selection' => 'Who cares',
24
+ 'Folder' => 'Unread',
25
+ }
26
+ ]
27
+ end
28
+
29
+ subject(:parser) { InstaReadability::InstapaperParser.new csv }
30
+
31
+ before do
32
+ CSV.stubs(:foreach).with(csv, headers: true).multiple_yields(*rows.collect{|row| [row]})
33
+ end
34
+
35
+ describe 'new' do
36
+ it 'sets the csv instance variable' do
37
+ expect(parser.instance_variable_get(:@csv_path)).to be csv
38
+ end
39
+ end
40
+
41
+ describe '.parse' do
42
+ it 'parses the csv into bookmarks' do
43
+ book_params1 = { url: 'http://t.co/4MPuTK9dXn', favorite: false, archive: true }
44
+ book_params2 = { url: 'http://t.co/guSIBHxBaV', favorite: true, archive: false }
45
+ book_params3 = { url: 'http://t.co/9FDQCZLDQm', favorite: false, archive: false }
46
+ bookmarks = [InstaReadability::Bookmark.new(book_params1), InstaReadability::Bookmark.new(book_params2), InstaReadability::Bookmark.new(book_params3)]
47
+
48
+ expect(parser.create_bookmarks).to eq bookmarks
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,9 @@
1
+ require 'bourne'
2
+ require 'mocha/api'
3
+ require 'vcr'
4
+ require 'ostruct'
5
+ require 'insta_readability'
6
+
7
+ RSpec.configure do |config|
8
+ config.mock_with :mocha
9
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: insta_readability
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Will Mernagh
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-17 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Upload exported Instapaper csv to Readability.com
15
+ email: wmernagh@gmail.com
16
+ executables:
17
+ - import
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - Gemfile.lock
24
+ - README.md
25
+ - bin/import
26
+ - insta_readability.gemspec
27
+ - lib/insta_readability.rb
28
+ - lib/insta_readability/auth.rb
29
+ - lib/insta_readability/bookmark.rb
30
+ - lib/insta_readability/cli.rb
31
+ - lib/insta_readability/importer.rb
32
+ - lib/insta_readability/instapaper_parser.rb
33
+ - lib/insta_readability/version.rb
34
+ - spec/insta_readability/auth_spec.rb
35
+ - spec/insta_readability/bookmark_spec.rb
36
+ - spec/insta_readability/cli_spec.rb
37
+ - spec/insta_readability/importer_spec.rb
38
+ - spec/insta_readability/instapaper_parser_spec.rb
39
+ - spec/spec_helper.rb
40
+ homepage: https://github.com/wmernagh/insta_readability
41
+ licenses: []
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 1.8.24
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: InstaReadability
64
+ test_files:
65
+ - spec/insta_readability/auth_spec.rb
66
+ - spec/insta_readability/bookmark_spec.rb
67
+ - spec/insta_readability/cli_spec.rb
68
+ - spec/insta_readability/importer_spec.rb
69
+ - spec/insta_readability/instapaper_parser_spec.rb
70
+ - spec/spec_helper.rb
71
+ has_rdoc: