insta_readability 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: