lard 0.0.6 → 0.0.8.alpha1

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/bin/lard +80 -153
  3. data/lib/lard.rb +119 -0
  4. metadata +8 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f99cc882f8a69da2bb153deaf6562413ffaf1ef30d6629891a759923e14cbcb
4
- data.tar.gz: ddd7735acd5db8b72210fe6cc479dfee474682f46f23eb0b1b4f9e91f2bc6096
3
+ metadata.gz: 9baa80628bf009726fbb8d62d56c85d86390609311fe42789c087862408631c1
4
+ data.tar.gz: f65898d7ba1842f8a3ba64ee4ebf96d018832470d7ce462a3042282d26032f90
5
5
  SHA512:
6
- metadata.gz: 374516a4d37c0b9a94a28ae94f7f42bbfb39db3a659018c26898119b6698a046b2b63e52446410973c3ae8c55bdc8addcfd71295dc0dfda53dab69f8dda2a852
7
- data.tar.gz: 3ba7229ed910834cdf4f7cf39cf5c925c76ef45d300be9010ef3225e88f0416c9ab3e7fc2337a6a2dffb85024bf58678512fc49b1c2b911ab3d3f53e5fa05ab4
6
+ metadata.gz: ddfbb8bb02065e7380acb453598b3e7bbdfd911ad0625495565d0708e1e87b0144f7612ba01f8bb13fbe806642ae1dd882c6a76c3a6d76d4e99be88a85ecf7fd
7
+ data.tar.gz: 52ce87ac6cee76ed629681331a50a0c1a4ab854884dcab12a89638ace3f7fbe2a0d304291868592d5b86571cb82ac0691a44c0323bb238bc7b9311a66500002a
data/bin/lard CHANGED
@@ -1,186 +1,70 @@
1
1
  #!/usr/bin/env ruby
2
- require 'httparty'
2
+
3
+ require 'date'
3
4
  require 'paint'
4
5
  require 'thor'
5
6
  require 'yaml'
6
-
7
- # Try to authenticate with ~/.lard.yml
8
- begin
9
- config = YAML.load_file File.expand_path('~/.lard.yml')
10
- rescue StandardError
11
- config = {}
12
- end
13
- begin
14
- token = config['token']
15
- rescue StandardError
16
- token = nil
17
- end
18
- $options = {
19
- headers: {
20
- 'Authorization' => "Token #{token}"
21
- }
22
- }
23
- $folders = []
24
-
25
- # A set of utility functions for working with the Larder HTTP API
26
- module LardHTTP
27
- def authorized
28
- # Assume Auth header longer than "Token " is authorized
29
- $options[:headers]['Authorization'].length > 6
30
- end
31
-
32
- def get(endpoint, params = nil)
33
- raise "You're not logged in! Run 'lard login' first." unless authorized
34
-
35
- query = { query: params }
36
- opts = $options.merge query
37
- res = self.class.get "#{prefix}#{endpoint}", opts
38
- parse_response res
39
- end
40
-
41
- def post(endpoint, args = {})
42
- raise "You're not logged in! Run 'lard login' first." unless authorized
43
-
44
- opts = {
45
- body: args.to_json,
46
- headers: {
47
- 'Content-Type' => 'application/json'
48
- }
49
- }
50
- opts[:headers].merge! $options[:headers]
51
- res = self.class.post "#{prefix}#{endpoint}", opts
52
- parse_response res
53
- end
54
-
55
- def parse_response(res)
56
- JSON.parse res.body, symbolize_names: true
57
- end
58
-
59
- def raw_get(url)
60
- raise "You're not logged in! Run 'lard login' first." unless authorized
61
-
62
- JSON.parse self.class.get(url, $options).body, symbolize_names: true
63
- end
64
-
65
- def prefix
66
- 'https://larder.io/api/1/@me/'
67
- end
68
-
69
- def get_folder_by_name(name)
70
- fetch_folders if $folders.empty?
71
- $folders.find do |folder|
72
- folder[:name] == name
7
+ require 'lard'
8
+
9
+ # rubocop: disable ClassLength
10
+ class LardCLI < Thor
11
+ def initialize(*args)
12
+ super
13
+
14
+ # Try to authenticate with ~/.lard.yml
15
+ begin
16
+ config = YAML.load_file File.expand_path('~/.lard.yml')
17
+ token = config['token']
18
+ rescue StandardError
19
+ # Catch any file error here because the user can run `lard login`
20
+ # to generate this config file, so we may be OK!
21
+ token = nil
73
22
  end
74
- end
75
23
 
76
- def print_folder_name(folder)
77
- print Paint[folder[:name], folder[:color]]
78
- puts ":\t#{folder[:links]} links"
24
+ @lard = Lard.new token
79
25
  end
80
26
 
81
- def fetch_tags
82
- res = get 'tags', limit: 200
83
- tags = res[:results] || []
84
-
85
- until res[:next].nil?
86
- res = raw_get res[:next]
87
- tags.push(*res[:results])
88
- end
89
-
90
- tags
91
- end
92
-
93
- def fetch_bookmarks(folder_id)
94
- res = get "folders/#{folder_id}", limit: 200
95
- bookmarks = res[:results] || []
96
-
97
- until res[:next].nil?
98
- res = raw_get res[:next]
99
- bookmarks.push(*res[:results])
100
- end
101
-
102
- bookmarks
103
- end
104
-
105
- def fetch_folders
106
- res = get 'folders', limit: 200
107
- $folders = res[:results]
108
-
109
- until res[:next].nil?
110
- res = raw_get res[:next]
111
- $folders.push(*res[:results])
112
- end
113
-
114
- # TODO: Cache these folders
115
- end
116
-
117
- # TODO: How can we reduce the AbcSize here further?
118
- # rubocop:disable AbcSize
119
- def print_bookmark(bookmark)
120
- puts Paint[(bookmark[:title]).to_s, :bright]
121
- puts " #{bookmark[:description]}" if bookmark[:description]
122
- puts " #{bookmark[:url]}"
123
-
124
- return if bookmark[:tags].nil? || bookmark[:tags].empty?
125
-
126
- print ' '
127
- bookmark[:tags].each do |tag|
128
- print Paint["##{tag[:name]}", tag[:color]]
129
- print ' '
130
- end
131
- puts ''
132
- end
133
- # rubocop:enable AbcSize
134
-
135
- def print_tag(tag)
136
- puts Paint["##{tag[:name]}", tag[:color]]
137
- end
138
- end
139
-
140
- class Lard < Thor
141
- include LardHTTP
142
- include HTTParty
143
- maintain_method_across_redirects
144
-
145
27
  desc 'user', 'Prints information about the logged-in user'
28
+
146
29
  def user
147
- puts get('user')
30
+ print_user @lard.get 'user'
148
31
  end
149
32
 
150
33
  desc 'folders', 'Lists all bookmark folders'
151
- def folders
152
- fetch_folders if $folders == []
153
34
 
154
- $folders.each do |folder|
35
+ def folders
36
+ @lard.folders.each do |folder|
155
37
  print_folder_name folder
156
38
  end
157
39
  end
158
40
 
159
41
  desc 'folder <NAME>', 'Lists all bookmarks in a given folder'
42
+
160
43
  def folder(name)
161
- folder = get_folder_by_name name
44
+ folder = @lard.get_folder_by_name name
162
45
  raise "Could not find a folder named #{name}!" unless folder
163
46
 
164
47
  print_folder_name folder
165
48
 
166
- bookmarks = fetch_bookmarks folder[:id]
49
+ bookmarks = @lard.bookmarks folder[:id]
167
50
  bookmarks.each do |bookmark|
168
51
  print_bookmark bookmark
169
52
  end
170
53
  end
171
54
 
172
55
  desc 'tags', 'Lists all tags'
56
+
173
57
  def tags
174
- tags = fetch_tags
175
- tags.each do |tag|
58
+ @lard.tags.each do |tag|
176
59
  print_tag tag
177
60
  end
178
61
  end
179
62
 
180
63
  desc 'search <QUERY>', 'Search for bookmarks'
64
+
181
65
  def search(*args)
182
66
  query = args.join ' '
183
- res = get 'search', q: query
67
+ res = @lard.get 'search', q: query
184
68
  raise "No booknarks found match #{query}!" if res[:results].empty?
185
69
 
186
70
  bookmarks = res[:results]
@@ -189,8 +73,9 @@ class Lard < Thor
189
73
  end
190
74
  end
191
75
 
192
- # rubocop: disable MethodLength
193
76
  desc 'login [TOKEN]', 'Log in to larder with your API token'
77
+
78
+ # rubocop: disable MethodLength
194
79
  def login(token = nil)
195
80
  unless token
196
81
  puts 'Enter your Larder API token to save to ~/.lard.yml.'
@@ -205,29 +90,70 @@ class Lard < Thor
205
90
  end
206
91
 
207
92
  puts 'Saved token to ~/.lard.yml'
93
+ # rubocop: enable MethodLength
208
94
  end
209
- # rubocop: enable MethodLength
210
95
 
211
96
  desc 'bookmark <FOLDER> <TITLE> <LINK> [tags...]',
212
97
  'Creates or edits a bookmark'
213
98
  option :description, aliases: :d
99
+
214
100
  def bookmark(folder, title, link, *tags)
215
- f = get_folder_by_name folder
101
+ f = @lard.get_folder_by_name folder
216
102
  raise "Could not find a folder named #{folder}!" unless f
217
103
 
218
- res = post 'links/add',
219
- 'title' => title, 'url' => link, 'tags' => tags,
220
- 'parent' => f[:id],
221
- 'description' => options[:description]
104
+ res = @lard.post 'links/add',
105
+ 'title' => title, 'url' => link, 'tags' => tags,
106
+ 'parent' => f[:id],
107
+ 'description' => options[:description]
222
108
 
223
109
  raise 'Unable to add bookmark!' if res[:error]
224
110
 
225
111
  print_bookmark res
226
112
  end
113
+
114
+ private
115
+
116
+ def print_folder_name(folder)
117
+ print Paint[folder[:name], folder[:color]]
118
+ puts ":\t#{folder[:links]} links"
119
+ end
120
+
121
+ # TODO: How can we reduce the AbcSize here further?
122
+ # rubocop: disable AbcSize
123
+ def print_bookmark(bookmark)
124
+ puts Paint[(bookmark[:title]).to_s, :bright]
125
+ puts " #{bookmark[:description]}" if bookmark[:description]
126
+ puts " #{bookmark[:url]}"
127
+
128
+ return if bookmark[:tags].nil? || bookmark[:tags].empty?
129
+
130
+ print ' '
131
+ bookmark[:tags].each do |tag|
132
+ print Paint["##{tag[:name]}", tag[:color]]
133
+ print ' '
134
+ end
135
+ puts ''
136
+ end
137
+
138
+ # rubocop: enable AbcSize
139
+
140
+ def print_tag(tag)
141
+ puts Paint["##{tag[:name]}", tag[:color]]
142
+ end
143
+
144
+ def print_user(user)
145
+ date = Date.strptime user[:date_joined]
146
+
147
+ print Paint[user[:username], :bright]
148
+ puts " (#{user[:first_name]} #{user[:last_name]})"
149
+ puts " Links: #{user[:links]}"
150
+ puts " Joined on: #{date.strftime('%F')}"
151
+ puts ' Trial membership active' if user[:is_trial]
152
+ end
227
153
  end
228
154
 
229
155
  begin
230
- Lard.start(ARGV)
156
+ LardCLI.start(ARGV)
231
157
  rescue StandardError => e
232
158
  STDERR.puts "Error: #{e.message}"
233
159
 
@@ -235,3 +161,4 @@ rescue StandardError => e
235
161
 
236
162
  exit 1
237
163
  end
164
+ # rubocop: enable ClassLength
data/lib/lard.rb ADDED
@@ -0,0 +1,119 @@
1
+ require 'net/http'
2
+ require 'json'
3
+
4
+ # A set of utility functions for working with the Larder HTTP API
5
+ class Lard
6
+ VERSION = '0.0.8.alpha1'.freeze
7
+
8
+ def initialize(token = nil)
9
+ @token = token
10
+ @folders = []
11
+ end
12
+
13
+ def authorized
14
+ !@token.nil?
15
+ end
16
+
17
+ def api_url_prefix
18
+ 'https://larder.io/api/1/@me/'
19
+ end
20
+
21
+ def get_folder_by_name(name)
22
+ folders if @folders.empty?
23
+ @folders.find do |folder|
24
+ folder[:name] == name
25
+ end
26
+ end
27
+
28
+ def tags
29
+ res = get 'tags', limit: 200
30
+ tags = res[:results] || []
31
+
32
+ until res[:next].nil?
33
+ res = get res[:next]
34
+ tags.push(*res[:results])
35
+ end
36
+
37
+ tags
38
+ end
39
+
40
+ def bookmarks(folder_id)
41
+ res = get "folders/#{folder_id}", limit: 200
42
+ bookmarks = res[:results] || []
43
+
44
+ until res[:next].nil?
45
+ res = get res[:next]
46
+ bookmarks.push(*res[:results])
47
+ end
48
+
49
+ bookmarks
50
+ end
51
+
52
+ def folders
53
+ res = get 'folders', limit: 200
54
+ @folders = res[:results] || @folders
55
+
56
+ until res[:next].nil?
57
+ res = get res[:next]
58
+ @folders.push(*res[:results])
59
+ end
60
+
61
+ @folders
62
+ end
63
+
64
+ # Perform a GET request to an endpoint in the Larder API
65
+ def get(url, params = nil)
66
+ raise "You're not logged in! Run 'lard login' first." unless authorized
67
+
68
+ # Make a URI based on whether we received a full URL or just endpoint
69
+ uri = prepare_uri url
70
+ uri.query = URI.encode_www_form params unless params.nil?
71
+
72
+ res = Net::HTTP.start uri.host, uri.port, use_ssl: true do |http|
73
+ http.request prepare_request 'get', uri
74
+ end
75
+ parse_response res
76
+ end
77
+
78
+ # Perform a POST request to an endpoint in the Larder API
79
+ # Posts args as JSON in the post body, where args is a hash
80
+ def post(endpoint, args = {})
81
+ raise "You're not logged in! Run 'lard login' first." unless authorized
82
+
83
+ uri = prepare_uri endpoint
84
+ request = prepare_request 'post', uri
85
+ request.set_form_data args
86
+ res = Net::HTTP.start uri.host, uri.port, use_ssl: true do |http|
87
+ http.request request
88
+ end
89
+ parse_response res
90
+ end
91
+
92
+ private
93
+
94
+ def prepare_uri(url)
95
+ if url.start_with?('http://', 'https://')
96
+ URI url
97
+ else
98
+ URI "#{api_url_prefix}#{url}/"
99
+ end
100
+ end
101
+
102
+ def prepare_request(method, uri)
103
+ case method
104
+ when 'get'
105
+ request = Net::HTTP::Get.new uri
106
+ when 'post'
107
+ request = Net::HTTP::Post.new uri
108
+ request.add_field 'Content-Type', 'application/json'
109
+ end
110
+ request.add_field 'Authorization', "Token #{@token}"
111
+ # TODO: How can we ensure this gets updated with every new version?
112
+ request.add_field 'User-Agent', "Lard/#{VERSION}"
113
+ request
114
+ end
115
+
116
+ def parse_response(res)
117
+ JSON.parse res.body, symbolize_names: true
118
+ end
119
+ end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.8.alpha1
5
5
  platform: ruby
6
6
  authors:
7
7
  - hawkins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-27 00:00:00.000000000 Z
11
+ date: 2018-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: httparty
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: 0.16.2
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: 0.16.2
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: paint
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -60,8 +46,10 @@ extensions: []
60
46
  extra_rdoc_files: []
61
47
  files:
62
48
  - bin/lard
63
- homepage:
64
- licenses: []
49
+ - lib/lard.rb
50
+ homepage: https://github.com/hawkins/lard
51
+ licenses:
52
+ - MIT
65
53
  metadata: {}
66
54
  post_install_message:
67
55
  rdoc_options: []
@@ -74,9 +62,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
74
62
  version: '0'
75
63
  required_rubygems_version: !ruby/object:Gem::Requirement
76
64
  requirements:
77
- - - ">="
65
+ - - ">"
78
66
  - !ruby/object:Gem::Version
79
- version: '0'
67
+ version: 1.3.1
80
68
  requirements: []
81
69
  rubyforge_project:
82
70
  rubygems_version: 2.7.7