pinup 0.1.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.
@@ -0,0 +1,25 @@
1
+ require 'launchy'
2
+
3
+ module Pinup
4
+ class Open
5
+ def self.open_pins(options = {})
6
+ unread = options[:unread] unless options[:unread].nil?
7
+ untagged = options[:untagged] unless options[:untagged].nil?
8
+ count = options[:number].to_i unless options[:number].nil?
9
+ delete = options[:delete] unless options[:delete].nil?
10
+
11
+ items = Pinup::Queries.list_items
12
+ filtered = Pinup::Queries.filter_items(items, unread, untagged, count)
13
+ items_string = Pinup::Queries.item_string(filtered)
14
+ urls = items_string.split(/\n/)
15
+
16
+ urls.each do |url|
17
+ Launchy.open(url)
18
+ end
19
+
20
+ if delete
21
+ Pinup::Queries.delete_items(urls)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,116 @@
1
+ require 'net/https'
2
+ require 'uri'
3
+ require 'json'
4
+
5
+ module Pinup
6
+ class Queries
7
+ def self.list_items
8
+ token = Pinup::Settings.get_token
9
+ if token.nil?
10
+ return nil
11
+ end
12
+
13
+ parameters = JSON_PARAMS.dup
14
+ parameters[:auth_token] = token
15
+
16
+ response = list_query(parameters)
17
+ if response.code != '200'
18
+ puts "Error getting bookmarks: #{ response.body }"
19
+ return nil
20
+ else
21
+ return response.body
22
+ end
23
+ end
24
+
25
+ def self.filter_items(response, unread, untagged, count)
26
+ begin
27
+ json = JSON.parse(response)
28
+ rescue JSON::ParserError => e
29
+ puts "Failed to parse JSON: #{ e }"
30
+ exit
31
+ end
32
+
33
+ count = 20 if count < 1
34
+ new_items = []
35
+
36
+ json.each do |item|
37
+ bookmark = Bookmark.new(item)
38
+
39
+ if unread && untagged
40
+ if bookmark.unread || bookmark.untagged
41
+ new_items << bookmark
42
+ end
43
+ elsif unread
44
+ if bookmark.unread && !bookmark.untagged
45
+ new_items << bookmark
46
+ end
47
+ elsif untagged
48
+ if bookmark.untagged && !bookmark.unread
49
+ new_items << bookmark
50
+ end
51
+ else
52
+ if !bookmark.unread && !bookmark.untagged
53
+ new_items << bookmark
54
+ end
55
+ end
56
+
57
+ if new_items.count >= count
58
+ break
59
+ end
60
+ end
61
+
62
+ return new_items
63
+ end
64
+
65
+ def self.delete_items(urls)
66
+ token = Pinup::Settings.get_token
67
+ if token.nil?
68
+ return nil
69
+ end
70
+
71
+ parameters = JSON_PARAMS.dup
72
+ parameters[:auth_token] = token
73
+
74
+ urls.each do |url|
75
+ url_params = parameters.dup
76
+ url_params[:url] = url
77
+ delete_query(url_params)
78
+ end
79
+ end
80
+
81
+ def self.item_string(items)
82
+ item_output = ""
83
+ items.each do |item|
84
+ item_output << "#{ item.href }\n"
85
+ end
86
+
87
+ return item_output
88
+ end
89
+
90
+ private
91
+
92
+ def self.list_query(parameters)
93
+ uri = URI.parse("#{ API_URL }/posts/all")
94
+ uri.query = URI.encode_www_form(parameters)
95
+
96
+ http = Net::HTTP.new(uri.host, uri.port)
97
+ http.use_ssl = true
98
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
99
+
100
+ request = Net::HTTP::Get.new(uri.request_uri)
101
+ http.request(request)
102
+ end
103
+
104
+ def self.delete_query(parameters)
105
+ uri = URI.parse("#{ API_URL }/posts/delete")
106
+ uri.query = URI.encode_www_form(parameters)
107
+
108
+ http = Net::HTTP.new(uri.host, uri.port)
109
+ http.use_ssl = true
110
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
111
+
112
+ request = Net::HTTP::Get.new(uri.request_uri)
113
+ http.request(request)
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,89 @@
1
+ require 'yaml'
2
+ require 'netrc'
3
+ require 'colored'
4
+
5
+ module Pinup
6
+ class Settings
7
+ def self.write_settings(settings)
8
+ File.open(SETTINGS, 'w') do |f|
9
+ f.write(settings.to_yaml)
10
+ end
11
+ end
12
+
13
+ def self.read_settings
14
+ if !File.exists? SETTINGS
15
+ return nil
16
+ end
17
+
18
+ settings = YAML::load_file(SETTINGS)
19
+ if !settings || settings.empty?
20
+ return nil
21
+ end
22
+
23
+ return settings
24
+ end
25
+
26
+ def self.save_token(options = {})
27
+ path = DEFAULT_NETRC
28
+ token = options[:token]
29
+
30
+ if token.nil?
31
+ puts 'Attempted to save empty token'.red
32
+ return nil
33
+ end
34
+
35
+ if options[:path]
36
+ path = options[:path]
37
+ end
38
+
39
+ token_split = token.split(/:/)
40
+ if token_split.count != 2
41
+ puts "Invalid token #{ token_split.join(':') }".red
42
+ return nil
43
+ end
44
+
45
+ username = token_split.first
46
+ password = token_split.last
47
+
48
+ netrc = Netrc.read(path)
49
+ netrc.new_item_prefix = "\n# This Entry was added automatically\n"
50
+ netrc[PINBOARD_URL] = username, password
51
+ netrc.save
52
+
53
+ return true
54
+ end
55
+
56
+ def self.get_token
57
+ path = DEFAULT_NETRC
58
+
59
+ settings = read_settings
60
+ if settings
61
+ path = settings[:path]
62
+ end
63
+
64
+ netrc = Netrc.read(path)
65
+ username, password = netrc[PINBOARD_URL]
66
+ token = token(username, password)
67
+ if token.nil?
68
+ puts "There are no credentials in #{ path }".red
69
+ return nil
70
+ end
71
+
72
+ return token
73
+ end
74
+
75
+ def self.clear_settings
76
+ if File.exists? SETTINGS
77
+ File.delete(SETTINGS)
78
+ end
79
+ end
80
+
81
+ def self.token(username, password)
82
+ if username.nil? || password.nil? || username.empty? || password.empty?
83
+ return nil
84
+ end
85
+
86
+ "#{ username }:#{ password }"
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,8 @@
1
+ module Pinup
2
+ VERSION = '0.1.0'
3
+ SETTINGS = File.expand_path('~/.pinup')
4
+ PINBOARD_URL = 'pinboard.in'
5
+ API_URL = 'https://api.pinboard.in/v1'
6
+ JSON_PARAMS = { format: 'json' }
7
+ DEFAULT_NETRC = File.expand_path('~/.netrc')
8
+ end
data/pinup.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ require File.join([File.dirname(__FILE__),'lib','pinup','version.rb'])
2
+ spec = Gem::Specification.new do |s|
3
+ s.name = 'pinup'
4
+ s.version = Pinup::VERSION
5
+ s.author = 'Keith Smiley'
6
+ s.email = 'keithbsmiley@gmail.com'
7
+ s.homepage = 'http://keith.so/'
8
+ s.required_ruby_version = '>= 1.9.3'
9
+ s.summary = 'Digest your Pinboard bookmarks in bulk'
10
+ s.description = 'Allows you to open and delete your Pinboard bookmarks in bulk'
11
+ s.license = 'MIT'
12
+
13
+ s.files = `git ls-files`.split($/)
14
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
16
+ s.require_paths = ['lib']
17
+
18
+ s.add_dependency('colored', '~> 1.2')
19
+ s.add_dependency('netrc', '~> 0.7.7')
20
+ s.add_dependency('launchy', '~> 2.3.0')
21
+ s.add_development_dependency('rake')
22
+ s.add_development_dependency('rspec', '~> 2.13.0')
23
+ s.add_runtime_dependency('gli','2.5.6')
24
+ end
@@ -0,0 +1,42 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Pinup::Authorize do
4
+ before do
5
+ @netrc_path = File.expand_path('~/foobar')
6
+ end
7
+
8
+ describe 'authorize_netrc' do
9
+ describe 'an empty netrc' do
10
+ it 'should return nil' do
11
+ expect(Pinup::Authorize.authorize_netrc({ path: @netrc_path })).to be_nil
12
+ end
13
+ end
14
+
15
+ describe 'a valid netrc' do
16
+ it 'should return true' do
17
+ # This will only pass if your default netrc has a valid username and password (token)
18
+ expect(Pinup::Authorize.authorize_netrc).to be_true
19
+ end
20
+ end
21
+ end
22
+
23
+ describe 'authorize_credentials' do
24
+ describe 'invalid credentials' do
25
+ it 'should return nil' do
26
+ expect(Pinup::Authorize.authorize_credentials({ username: 'foo', password: 'bar' })).to be_nil
27
+ end
28
+ end
29
+
30
+ describe 'valid credentials' do
31
+ # Note: this will only work if you set up netrc's for this testing
32
+ it 'should return true' do
33
+ netrc = Netrc.read
34
+ username, password = netrc['test.pinboard.in']
35
+ expect(username).not_to be_nil
36
+ expect(password).not_to be_nil
37
+ result = Pinup::Authorize.authorize_credentials({ username: username, password: password })
38
+ expect(result).to be_true
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,97 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Bookmark do
4
+ describe 'attributes' do
5
+ before do
6
+ options = { 'href' => 'http://github.com', 'toread' => 'yes', 'tags' => '' }
7
+ @bookmark = Bookmark.new(options)
8
+ end
9
+
10
+ it 'should respond to the correct attributes' do
11
+ expect(@bookmark).to respond_to(:href)
12
+ expect(@bookmark).to respond_to(:unread)
13
+ expect(@bookmark).to respond_to(:untagged)
14
+ expect(@bookmark).not_to respond_to(:foobar)
15
+ end
16
+ end
17
+
18
+ describe 'initialize' do
19
+ describe 'unread without tags' do
20
+ before do
21
+ options = { 'href' => 'http://github.com', 'toread' => 'yes', 'tags' => '' }
22
+ @bookmark = Bookmark.new(options)
23
+ end
24
+
25
+ it 'have the correct attributes' do
26
+ expect(@bookmark).not_to be_nil
27
+ result = @bookmark.href == 'http://github.com'
28
+ expect(result).to be_true
29
+ expect(@bookmark.unread).to be_true
30
+ expect(@bookmark.untagged).to be_true
31
+ end
32
+ end
33
+
34
+ describe 'read with tags' do
35
+ before do
36
+ options = { 'href' => 'http://google.com', 'toread' => 'no', 'tags' => 'foo' }
37
+ @bookmark = Bookmark.new(options)
38
+ end
39
+
40
+ it 'have the correct attributes' do
41
+ expect(@bookmark).not_to be_nil
42
+ result = @bookmark.href == 'http://google.com'
43
+ expect(result).to be_true
44
+ expect(@bookmark.unread).to be_false
45
+ expect(@bookmark.untagged).to be_false
46
+ end
47
+ end
48
+ end
49
+
50
+ describe 'is_unread' do
51
+ it 'should return true only when toread is "yes"' do
52
+ expect(Bookmark.is_unread('yes')).to be_true
53
+ end
54
+
55
+ it 'should return false otherwise' do
56
+ expect(Bookmark.is_unread('false')).to be_false
57
+ expect(Bookmark.is_unread('no')).to be_false
58
+ expect(Bookmark.is_unread('foo')).to be_false
59
+ end
60
+ end
61
+
62
+
63
+ describe 'is_untagged' do
64
+ it 'should return true if there is nothing in the tag field' do
65
+ expect(Bookmark.is_untagged(' ')).to be_true
66
+ expect(Bookmark.is_untagged("\n \t \r")).to be_true
67
+ end
68
+
69
+ it 'should return false if there is something in the tag field' do
70
+ expect(Bookmark.is_untagged('foo')).to be_false
71
+ expect(Bookmark.is_untagged('foo bar')).to be_false
72
+ end
73
+ end
74
+
75
+ describe 'to_s' do
76
+ before do
77
+ options = { 'href' => 'http://google.com', 'toread' => 'no', 'tags' => 'foo' }
78
+ @bookmark = Bookmark.new(options)
79
+ @response = @bookmark.to_s
80
+ end
81
+
82
+ it 'should contain the URL' do
83
+ result = @response.include? 'google.com'
84
+ expect(result).to be_true
85
+ end
86
+
87
+ it 'should contain unread settings' do
88
+ result = @response.include? 'Unread: false'
89
+ expect(result).to be_true
90
+ end
91
+
92
+ it 'should contain the URL' do
93
+ result = @response.include? 'Untagged: false'
94
+ expect(result).to be_true
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,132 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Pinup::Queries do
4
+ describe 'list_items' do
5
+ before do
6
+ items = Pinup::Queries.list_items
7
+ @posts = JSON.parse(items)
8
+ end
9
+
10
+ it 'shoud return some number of items' do
11
+ result = @posts.count > 0
12
+ expect(result).to be_true
13
+ end
14
+ end
15
+
16
+ describe 'filter_items' do
17
+ describe 'read/unread items' do
18
+ describe 'unread items' do
19
+ before do
20
+ items = Pinup::Queries.list_items
21
+ @filtered = Pinup::Queries.filter_items(items, true, false, 20)
22
+ end
23
+
24
+ it 'should return only unread items' do
25
+ @filtered.each do |item|
26
+ expect(item.unread).to be_true
27
+ expect(item.untagged).to be_false
28
+ end
29
+ end
30
+ end
31
+
32
+ describe 'read items' do
33
+ before do
34
+ items = Pinup::Queries.list_items
35
+ @filtered = Pinup::Queries.filter_items(items, false, false, 20)
36
+ end
37
+
38
+ it 'should return only read items' do
39
+ @filtered.each do |item|
40
+ expect(item.unread).to be_false
41
+ expect(item.untagged).to be_false
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ describe 'untagged/tagged items' do
48
+ describe 'untagged items' do
49
+ before do
50
+ items = Pinup::Queries.list_items
51
+ @filtered = Pinup::Queries.filter_items(items, false, true, 20)
52
+ end
53
+
54
+ it 'should return only untagged items' do
55
+ @filtered.each do |item|
56
+ expect(item.unread).to be_false
57
+ expect(item.untagged).to be_true
58
+ end
59
+ end
60
+ end
61
+
62
+ describe 'tagged items' do
63
+ before do
64
+ items = Pinup::Queries.list_items
65
+ @filtered = Pinup::Queries.filter_items(items, false, false, 20)
66
+ end
67
+
68
+ it 'should return only untagged items' do
69
+ result = @filtered.count > 0
70
+ expect(result).to be_true
71
+ @filtered.each do |item|
72
+ expect(item.unread).to be_false
73
+ expect(item.untagged).to be_false
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ # Note these will only work if the default pinboard account unread & untagged items
80
+ describe 'number of items' do
81
+ describe 'an invalid number' do
82
+ describe 'zero items' do
83
+ before do
84
+ items = Pinup::Queries.list_items
85
+ @filtered = Pinup::Queries.filter_items(items, false, false, 0)
86
+ end
87
+
88
+ it 'should return the default number of items' do
89
+ expect(@filtered.count).to equal(20)
90
+ end
91
+ end
92
+
93
+ describe 'negative items' do
94
+ before do
95
+ items = Pinup::Queries.list_items
96
+ @filtered = Pinup::Queries.filter_items(items, false, false, -9)
97
+ end
98
+
99
+ it 'should return the default number of items' do
100
+ expect(@filtered.count).to equal(20)
101
+ end
102
+ end
103
+ end
104
+
105
+ describe 'some number of unread items' do
106
+ before do
107
+ items = Pinup::Queries.list_items
108
+ @filtered = Pinup::Queries.filter_items(items, false, false, 14)
109
+ end
110
+
111
+ it 'should return the correct number of items' do
112
+ expect(@filtered.count).to equal(14)
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ describe 'item_string' do
119
+ before do
120
+ @item = Bookmark.new({ "href" => "http://google.com" })
121
+ @item2 = Bookmark.new({ "href" => "http://github.com" })
122
+ @urls = [ @item, @item2 ]
123
+ @response = Pinup::Queries.item_string(@urls)
124
+ @string = "http://google.com\nhttp://github.com\n"
125
+ end
126
+
127
+ it 'should return a correctly formatted string' do
128
+ result = @response == @string
129
+ expect(result).to be_true
130
+ end
131
+ end
132
+ end