delicious-cli 0.1.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.
- data/LICENSE +20 -0
- data/README.rdoc +63 -0
- data/bin/dels +6 -0
- data/lib/delicious-cli/api.rb +36 -0
- data/lib/delicious-cli/db.rb +113 -0
- data/lib/delicious-cli/display.rb +51 -0
- data/lib/delicious-cli/log.rb +7 -0
- data/lib/delicious-cli/settings.rb +60 -0
- data/lib/delicious-cli.rb +156 -0
- data/test/delicious-cli_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +93 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Chris Gahan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
= delicious-cli
|
2
|
+
|
3
|
+
Locally mirror your delicious links, then search them. Example:
|
4
|
+
|
5
|
+
dels <search query>
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
gem sources --add http://gemcutter.org
|
10
|
+
gem install delicious-cli
|
11
|
+
|
12
|
+
== Example:
|
13
|
+
|
14
|
+
=== Setting your delicious username/password:
|
15
|
+
|
16
|
+
epi@fizz$ dels -c
|
17
|
+
|
18
|
+
Delicious login info
|
19
|
+
---------------------------
|
20
|
+
|
21
|
+
Username: mydeliciouslogin
|
22
|
+
Password: mypassword
|
23
|
+
|
24
|
+
User: "mydeliciouslogin" | Pass: "mypassword"
|
25
|
+
Is this correct? [y/N] y
|
26
|
+
|
27
|
+
* Checking that login/password works...
|
28
|
+
|_ Login successful! Saving config...
|
29
|
+
|
30
|
+
|
31
|
+
=== Downloading all your delicious links:
|
32
|
+
|
33
|
+
epi@fizz$ dels -r
|
34
|
+
|
35
|
+
* Redownloading database...
|
36
|
+
* Retrieving all links... (3465 links found)
|
37
|
+
* Inserting links into database...done!
|
38
|
+
|
39
|
+
=== Downloading new links (since last sync):
|
40
|
+
|
41
|
+
epi@fizz$ dels -s
|
42
|
+
|
43
|
+
* Synchronizing database...
|
44
|
+
* Retrieving new links... (5 links found)
|
45
|
+
* Inserting links into database...done!
|
46
|
+
|
47
|
+
== Commandline options:
|
48
|
+
|
49
|
+
Usage: dels [options] <search query>
|
50
|
+
|
51
|
+
Specific options:
|
52
|
+
-d, --debug Debug info
|
53
|
+
-s, --sync Synchronize links
|
54
|
+
-r, --redownload Erase database and redownload all links
|
55
|
+
-c, --config Configure app (set delicious username/password)
|
56
|
+
-t, --test-auth Test that authentication info works
|
57
|
+
|
58
|
+
Common options:
|
59
|
+
-h, --help Show this message
|
60
|
+
|
61
|
+
== Copyright
|
62
|
+
|
63
|
+
Copyright (c) 2009 Chris Gahan. See LICENSE for details.
|
data/bin/dels
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'delicious-cli/settings'
|
3
|
+
|
4
|
+
# Documentation:
|
5
|
+
# http://delicious.com/help/api
|
6
|
+
|
7
|
+
class Delicious
|
8
|
+
include HTTParty
|
9
|
+
base_uri 'api.del.icio.us:443/v1'
|
10
|
+
format :xml
|
11
|
+
|
12
|
+
def self.posts_update
|
13
|
+
result = get('/posts/update')
|
14
|
+
if result["update"]
|
15
|
+
result["update"]["time"]
|
16
|
+
else
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.posts_all(options={})
|
22
|
+
result = get('/posts/all', :query=>options)
|
23
|
+
[result["posts"]["post"]].flatten # ensure it's an array
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.posts_since(time)
|
27
|
+
$log.debug "Retrieving links newer than #{time}"
|
28
|
+
results = posts_all(:fromdt=>time)
|
29
|
+
results.select { |r| r["time"] != time }
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.valid_auth?
|
33
|
+
not posts_update.nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
require 'sequel/extensions/blank'
|
3
|
+
|
4
|
+
require 'delicious-cli/settings'
|
5
|
+
require 'delicious-cli/api'
|
6
|
+
|
7
|
+
#################################################################
|
8
|
+
|
9
|
+
$log.debug "Loading database..."
|
10
|
+
DB = Sequel.sqlite(configfile('delicious.db'))
|
11
|
+
$log.debug "done."
|
12
|
+
|
13
|
+
#################################################################
|
14
|
+
|
15
|
+
=begin
|
16
|
+
Sample record:
|
17
|
+
|
18
|
+
{
|
19
|
+
"href"=>"http://guru.com/",
|
20
|
+
"time"=>"2009-04-24T06:06:37Z",
|
21
|
+
"hash"=>"80e9a5f0bccb7f9e9dfd2e309eabd7de",
|
22
|
+
"tag"=>"jobs business freelance employment outsourcing exchanges networking",
|
23
|
+
"meta"=>"485e955fe2937fbef85390623ad0984c",
|
24
|
+
"description"=>"Guru.com",
|
25
|
+
"extended"=>"Worldwide freelancer marketplace."
|
26
|
+
}
|
27
|
+
=end
|
28
|
+
|
29
|
+
#################################################################
|
30
|
+
|
31
|
+
class Database
|
32
|
+
@@posts = DB[:posts]
|
33
|
+
|
34
|
+
def self.init!
|
35
|
+
create_posts! unless DB.table_exists?(:posts)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.clear!
|
39
|
+
DB.drop_table(:posts)
|
40
|
+
create_posts!
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.create_posts!
|
44
|
+
DB.create_table :posts do
|
45
|
+
primary_key :id
|
46
|
+
|
47
|
+
string :href
|
48
|
+
string :time
|
49
|
+
string :tag
|
50
|
+
string :description
|
51
|
+
text :extended
|
52
|
+
string :hash
|
53
|
+
string :meta
|
54
|
+
|
55
|
+
index :hash, {:unique=>true}
|
56
|
+
index [:description, :extended, :tag]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.sync(all=false)
|
61
|
+
all = true if @@posts.empty?
|
62
|
+
|
63
|
+
if all
|
64
|
+
print "* Retrieving all links..."
|
65
|
+
STDOUT.flush
|
66
|
+
posts = Delicious.posts_all
|
67
|
+
else
|
68
|
+
print "* Retrieving new links..."
|
69
|
+
STDOUT.flush
|
70
|
+
posts = Delicious.posts_since(most_recent_time)
|
71
|
+
end
|
72
|
+
|
73
|
+
$log.debug "sync: got #{posts.size} posts"
|
74
|
+
|
75
|
+
puts " (#{posts.size} links found)"
|
76
|
+
|
77
|
+
return if posts.empty?
|
78
|
+
|
79
|
+
print "* Inserting links into database..."
|
80
|
+
|
81
|
+
counter = 0
|
82
|
+
for post in posts
|
83
|
+
counter += 1
|
84
|
+
begin
|
85
|
+
add post
|
86
|
+
rescue Sequel::DatabaseError => e
|
87
|
+
$log.debug "error: #{e} adding #{post.inspect}"
|
88
|
+
end
|
89
|
+
|
90
|
+
if counter % 37 == 0
|
91
|
+
print "."
|
92
|
+
STDOUT.flush
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
puts "done!"
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.most_recent_time
|
100
|
+
@@posts.order(:time.desc).limit(1).first[:time]
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.add(params)
|
104
|
+
@@posts << params
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.find(query)
|
108
|
+
query = "%#{query}%" if query.is_a? String
|
109
|
+
@@posts.filter(:extended.like(query) | :description.like(query) | :tag.like(query)).order(:time)
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'colorize'
|
3
|
+
|
4
|
+
#################################################################
|
5
|
+
## Load the colorize gem, and define the "hilite" function
|
6
|
+
begin
|
7
|
+
require 'rubygems'
|
8
|
+
require 'colorize'
|
9
|
+
# Colourized hilite...
|
10
|
+
class String
|
11
|
+
def hilite(query, color=:white)
|
12
|
+
query = Regexp.new( Regexp.escape(query), Regexp::IGNORECASE )
|
13
|
+
self.to_s.send(color).gsub(/(.*)(#{query})(.*)/) { $1.send(color) + $2.black.on_yellow + $3.send(color)}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
rescue LoadError
|
17
|
+
STDERR.puts "Note: You should install the 'colorize' gem for extra prettiness.\n"
|
18
|
+
# Monochrome hilite does nothing...
|
19
|
+
class String
|
20
|
+
def hilite(query); self; end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
#################################################################
|
25
|
+
|
26
|
+
def formatdate(date, width=11)
|
27
|
+
dt = DateTime.parse(date)
|
28
|
+
time = "%l:%M%P"
|
29
|
+
date = "%d %b %g"
|
30
|
+
#dt.strftime("#{date} #{time}")
|
31
|
+
result = dt.strftime(date)
|
32
|
+
|
33
|
+
result.ljust(width).light_yellow
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def display(post, query, indent_size=11)
|
38
|
+
indent = " " * indent_size
|
39
|
+
|
40
|
+
date = formatdate(post[:time], indent_size)
|
41
|
+
desc = post[:description].hilite(query, :light_white)
|
42
|
+
ext = post[:extended].hilite(query, :white)
|
43
|
+
url = post[:href].hilite(query, :light_blue)
|
44
|
+
tags = post[:tag].hilite(query, :light_cyan)
|
45
|
+
|
46
|
+
puts date + desc
|
47
|
+
puts indent + ext if post[:extended].any?
|
48
|
+
puts indent + url
|
49
|
+
puts indent + "(".cyan + tags + ")".cyan
|
50
|
+
puts
|
51
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
require 'delicious-cli/log'
|
5
|
+
|
6
|
+
#################################################################
|
7
|
+
HOMEDIR = File.expand_path("~")
|
8
|
+
CONFIGDIR = File.join(HOMEDIR, ".delicious")
|
9
|
+
#################################################################
|
10
|
+
|
11
|
+
#################################################################
|
12
|
+
class FileNotFound < IOError; end
|
13
|
+
#################################################################
|
14
|
+
|
15
|
+
#################################################################
|
16
|
+
def configfile(filename, check=false)
|
17
|
+
path = File.join(CONFIGDIR, filename)
|
18
|
+
|
19
|
+
if check and not File.exists? path
|
20
|
+
raise FileNotFound, path
|
21
|
+
end
|
22
|
+
|
23
|
+
path
|
24
|
+
end
|
25
|
+
#################################################################
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
#################################################################
|
30
|
+
|
31
|
+
unless File.exists? CONFIGDIR
|
32
|
+
$log.info "* Creating new config directory: #{CONFIGDIR}"
|
33
|
+
FileUtils.mkdir_p CONFIGDIR
|
34
|
+
end
|
35
|
+
|
36
|
+
class Settings
|
37
|
+
|
38
|
+
def self.settings
|
39
|
+
@settings ||= {}
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.[](key)
|
43
|
+
settings[key]
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.[]=(key, val)
|
47
|
+
settings[key] = val
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.load!
|
51
|
+
@settings = YAML::load_file( configfile('settings.yml') )
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.save!
|
55
|
+
open( configfile('settings.yml'), "w" ) do |f|
|
56
|
+
f.write YAML::dump(settings)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#################################################################
|
4
|
+
|
5
|
+
require "delicious-cli/log"
|
6
|
+
|
7
|
+
libs = %w[
|
8
|
+
rubygems
|
9
|
+
|
10
|
+
optparse
|
11
|
+
optparse/time
|
12
|
+
ostruct
|
13
|
+
|
14
|
+
delicious-cli/db
|
15
|
+
delicious-cli/display
|
16
|
+
delicious-cli/api
|
17
|
+
delicious-cli/settings
|
18
|
+
]
|
19
|
+
|
20
|
+
libs.each do |lib|
|
21
|
+
#$log.debug "loading #{lib}"
|
22
|
+
require lib
|
23
|
+
end
|
24
|
+
|
25
|
+
#################################################################
|
26
|
+
|
27
|
+
def search(query)
|
28
|
+
matches = Database.find(query)
|
29
|
+
matches.each { |match| display(match, query) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def sync
|
33
|
+
puts "* Synchronizing database..."
|
34
|
+
Database.sync
|
35
|
+
end
|
36
|
+
|
37
|
+
def redownload
|
38
|
+
puts "* Redownloading database..."
|
39
|
+
Database.clear!
|
40
|
+
Database.sync
|
41
|
+
end
|
42
|
+
|
43
|
+
def config
|
44
|
+
# prompt user and stuff
|
45
|
+
puts "Delicious login info"
|
46
|
+
puts "---------------------------"
|
47
|
+
puts
|
48
|
+
print "Username: "
|
49
|
+
username = gets.strip
|
50
|
+
print "Password: "
|
51
|
+
password = gets.strip
|
52
|
+
|
53
|
+
puts
|
54
|
+
puts "User: #{username.inspect} | Pass: #{password.inspect}"
|
55
|
+
print "Is this correct? [y/N] "
|
56
|
+
answer = gets.strip
|
57
|
+
if answer =~ /^[Yy]$/
|
58
|
+
puts
|
59
|
+
|
60
|
+
puts "* Checking that login/password works..."
|
61
|
+
Delicious.basic_auth(username, password)
|
62
|
+
if Delicious.valid_auth?
|
63
|
+
puts " |_ Login successful! Saving config..."
|
64
|
+
Settings["username"] = username
|
65
|
+
Settings["password"] = password
|
66
|
+
Settings.save!
|
67
|
+
else
|
68
|
+
puts " |_ Login failed! (Please check your credentials or network.)"
|
69
|
+
end
|
70
|
+
puts
|
71
|
+
else
|
72
|
+
puts "Aborting..."
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
#################################################################
|
78
|
+
|
79
|
+
def main
|
80
|
+
|
81
|
+
# In it!
|
82
|
+
|
83
|
+
Database.init!
|
84
|
+
Settings.load!
|
85
|
+
|
86
|
+
Delicious.basic_auth(Settings["username"], Settings["password"])
|
87
|
+
|
88
|
+
# Parse de opts
|
89
|
+
|
90
|
+
ARGV.push("--help") if ARGV.empty?
|
91
|
+
|
92
|
+
options = OpenStruct.new
|
93
|
+
OptionParser.new do |opts|
|
94
|
+
opts.banner = "Usage: dels [options] <search query>"
|
95
|
+
opts.separator ""
|
96
|
+
opts.separator "Specific options:"
|
97
|
+
|
98
|
+
opts.on("-d", "--debug", "Debug info") do |opt|
|
99
|
+
options.debug = true
|
100
|
+
end
|
101
|
+
|
102
|
+
opts.on("-s", "--sync", "Synchronize links") do |opt|
|
103
|
+
options.sync = true
|
104
|
+
end
|
105
|
+
|
106
|
+
opts.on("-r", "--redownload", "Erase database and redownload all links") do |opt|
|
107
|
+
options.redownload = true
|
108
|
+
end
|
109
|
+
|
110
|
+
opts.on("-c", "--config", "Configure app (set delicious username/password)") do |opt|
|
111
|
+
options.config = true
|
112
|
+
end
|
113
|
+
|
114
|
+
opts.on("-t", "--test-auth", "Test that authentication info works") do |opt|
|
115
|
+
options.test_auth = true
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
opts.separator ""
|
120
|
+
opts.separator "Common options:"
|
121
|
+
|
122
|
+
# No argument, shows at tail. This will print an options summary.
|
123
|
+
# Try it and see!
|
124
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
125
|
+
puts opts
|
126
|
+
puts
|
127
|
+
exit
|
128
|
+
end
|
129
|
+
|
130
|
+
end.parse!
|
131
|
+
|
132
|
+
|
133
|
+
# Handle options
|
134
|
+
|
135
|
+
$log.level = Logger::DEBUG if options.debug
|
136
|
+
|
137
|
+
if options.test_auth
|
138
|
+
puts "Logging in as '#{Settings["username"]}': #{Delicious.valid_auth? ? "success!" : "fail!"}"
|
139
|
+
elsif options.config
|
140
|
+
config
|
141
|
+
elsif options.redownload
|
142
|
+
redownload
|
143
|
+
elsif options.sync
|
144
|
+
sync
|
145
|
+
else
|
146
|
+
exit 1 unless query = ARGV[0]
|
147
|
+
query = ARGV[0]
|
148
|
+
search(query)
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
if $0 == __FILE__
|
155
|
+
main
|
156
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: delicious-cli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- epitron
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-08-29 00:00:00 -04:00
|
13
|
+
default_executable: dels
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: sequel
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: httparty
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: colorize
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
description: A commandline tool which lets you download all your delicious.com links into a local SQLite database and search them (with pretty color-coded results).
|
46
|
+
email: chris@ill-logic.com
|
47
|
+
executables:
|
48
|
+
- dels
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- LICENSE
|
53
|
+
- README.rdoc
|
54
|
+
files:
|
55
|
+
- lib/delicious-cli.rb
|
56
|
+
- lib/delicious-cli/api.rb
|
57
|
+
- lib/delicious-cli/db.rb
|
58
|
+
- lib/delicious-cli/display.rb
|
59
|
+
- lib/delicious-cli/log.rb
|
60
|
+
- lib/delicious-cli/settings.rb
|
61
|
+
- LICENSE
|
62
|
+
- README.rdoc
|
63
|
+
has_rdoc: true
|
64
|
+
homepage: http://github.com/epitron/delicious-cli
|
65
|
+
licenses: []
|
66
|
+
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options:
|
69
|
+
- --charset=UTF-8
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: "0"
|
83
|
+
version:
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.3.3
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: Delicious.com commandline interface
|
91
|
+
test_files:
|
92
|
+
- test/delicious-cli_test.rb
|
93
|
+
- test/test_helper.rb
|