instapaper_full 0.1.1 → 0.2.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.
- data/README.md +10 -3
- data/Rakefile +8 -0
- data/instapaper_full.gemspec +4 -2
- data/lib/errors.rb +13 -0
- data/lib/instapaper_full.rb +48 -45
- data/lib/instapaper_full/version.rb +1 -1
- data/test/asset_helpers.rb +9 -0
- data/test/http_responses/access_token_failure.txt +14 -0
- data/test/http_responses/access_token_success.txt +14 -0
- data/test/http_responses/bookmarks_add_failure.txt +14 -0
- data/test/http_responses/bookmarks_get_text_failure.txt +14 -0
- data/test/http_responses/bookmarks_get_text_success.txt +436 -0
- data/test/http_responses/bookmarks_list_success.txt +14 -0
- data/test/http_responses/verify_credentials_success.txt +14 -0
- data/test/instapaper_api_test.rb +115 -0
- data/test/test_helper.rb +12 -0
- metadata +67 -17
data/README.md
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
Ruby wrapper for the [Instapaper Full API](http://www.instapaper.com/api/full)
|
4
4
|
|
5
|
-
Draft version.
|
6
|
-
|
7
5
|
Note that you need to [request OAuth Application tokens manually](http://www.instapaper.com/main/request_oauth_consumer_token) and that most methods only work for Instapaper subscribers.
|
8
6
|
|
9
7
|
# Installation
|
@@ -15,4 +13,13 @@ Note that you need to [request OAuth Application tokens manually](http://www.ins
|
|
15
13
|
ip = InstapaperFull::API.new :consumer_key => "my key", :consumer_secret => "my secret"
|
16
14
|
ip.authenticate "someone@example.com", "password"
|
17
15
|
puts ip.options.user_id
|
18
|
-
|
16
|
+
ip.bookmarks_list(:limit => 1) do |b|
|
17
|
+
if b['type'] == 'bookmark'
|
18
|
+
puts b['url']
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Authors
|
23
|
+
|
24
|
+
* [Matt Biddulph](http://github.com/mattb)
|
25
|
+
* [Tom Taylor / Newspaper Club](http://github.com/tomtaylor)
|
data/Rakefile
CHANGED
data/instapaper_full.gemspec
CHANGED
@@ -6,8 +6,8 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = "instapaper_full"
|
7
7
|
s.version = InstapaperFull::VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = ["Matt Biddulph"]
|
10
|
-
s.email = ["mb@hackdiary.com"]
|
9
|
+
s.authors = ["Matt Biddulph", "Tom Taylor"]
|
10
|
+
s.email = ["mb@hackdiary.com", "tom@tomtaylor.co.uk"]
|
11
11
|
s.homepage = "https://github.com/mattb/instapaper_full"
|
12
12
|
s.summary = %q{Wrapper for the Instapaper Full Developer API}
|
13
13
|
s.description = %q{See http://www.instapaper.com/api/full}
|
@@ -26,4 +26,6 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.add_dependency("yajl-ruby", "~> 1.1.0")
|
27
27
|
|
28
28
|
s.add_development_dependency("rake")
|
29
|
+
s.add_development_dependency("test-unit", "~> 2.4.2")
|
30
|
+
s.add_development_dependency("webmock", "~> 1.7.8")
|
29
31
|
end
|
data/lib/errors.rb
ADDED
data/lib/instapaper_full.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'errors'
|
1
2
|
require 'json'
|
2
3
|
require 'faraday/request/oauth'
|
3
4
|
require 'faraday/response/parse_json'
|
@@ -5,37 +6,31 @@ require 'faraday/response/parse_json'
|
|
5
6
|
module InstapaperFull
|
6
7
|
class API
|
7
8
|
attr_accessor :options
|
8
|
-
def initialize(options={})
|
9
|
+
def initialize(options = {})
|
9
10
|
@options = options
|
10
11
|
end
|
11
12
|
|
12
13
|
def connection(options = {})
|
13
|
-
skip_json = options.delete(:skip_json)
|
14
|
-
|
15
14
|
options.merge!({
|
16
15
|
:proxy => @options[:proxy],
|
17
16
|
:ssl => {:verify => false},
|
18
17
|
:url => "https://www.instapaper.com/api/1/"
|
19
18
|
})
|
20
19
|
|
21
|
-
|
20
|
+
oauth_params = {
|
22
21
|
:consumer_key => @options[:consumer_key],
|
23
22
|
:consumer_secret => @options[:consumer_secret]
|
24
23
|
}
|
25
24
|
|
26
25
|
if authenticated?
|
27
|
-
|
28
|
-
|
26
|
+
oauth_params[:token] = @options[:oauth_token]
|
27
|
+
oauth_params[:token_secret] = @options[:oauth_token_secret]
|
29
28
|
end
|
30
29
|
|
31
30
|
Faraday.new(options) do |builder|
|
32
|
-
builder.use Faraday::Request::OAuth,
|
31
|
+
builder.use Faraday::Request::OAuth, oauth_params
|
33
32
|
builder.use Faraday::Request::UrlEncoded
|
34
|
-
builder.use Faraday::Response::Logger
|
35
33
|
builder.adapter Faraday.default_adapter
|
36
|
-
if authenticated? && !skip_json
|
37
|
-
builder.use Faraday::Response::ParseJson
|
38
|
-
end
|
39
34
|
end
|
40
35
|
end
|
41
36
|
|
@@ -43,10 +38,10 @@ module InstapaperFull
|
|
43
38
|
@options.has_key? :oauth_token and @options.has_key? :oauth_token_secret
|
44
39
|
end
|
45
40
|
|
46
|
-
def authenticate(username,password)
|
41
|
+
def authenticate(username, password)
|
47
42
|
@options.delete(:oauth_token)
|
48
43
|
@options.delete(:oauth_token_secret)
|
49
|
-
result = connection.post 'oauth/access_token' do |r|
|
44
|
+
result = connection.post 'oauth/access_token' do |r|
|
50
45
|
r.body = { :x_auth_username => username, :x_auth_password => password, :x_auth_mode => "client_auth" }
|
51
46
|
end
|
52
47
|
if result.status == 200
|
@@ -64,73 +59,81 @@ module InstapaperFull
|
|
64
59
|
end
|
65
60
|
end
|
66
61
|
|
67
|
-
def call(method,
|
68
|
-
|
69
|
-
|
70
|
-
|
62
|
+
def call(method, params = {}, connection_options = {})
|
63
|
+
result = connection(connection_options).post(method) do |r|
|
64
|
+
r.body = params unless params.empty?
|
65
|
+
end
|
66
|
+
|
67
|
+
if result.headers['content-type'] == 'application/json'
|
68
|
+
JSON.parse(result.body).tap do |d|
|
69
|
+
if error = d.find { |e| e['type'] == 'error' }
|
70
|
+
raise InstapaperFull::API::Error.new(error['error_code'], error['message'])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
else
|
74
|
+
raise InstapaperFull::API::Error.new(-1, result.body) if result.status != 200
|
75
|
+
result.body
|
71
76
|
end
|
72
|
-
return result.body
|
73
77
|
end
|
74
78
|
|
75
79
|
def verify_credentials
|
76
80
|
call('account/verify_credentials')[0]
|
77
81
|
end
|
78
82
|
|
79
|
-
def bookmarks_list(
|
80
|
-
call('bookmarks/list',
|
83
|
+
def bookmarks_list(params = {})
|
84
|
+
call('bookmarks/list', params)
|
81
85
|
end
|
82
86
|
|
83
|
-
def bookmarks_update_read_progress(
|
84
|
-
call('bookmarks/update_read_progress',
|
87
|
+
def bookmarks_update_read_progress(params = {})
|
88
|
+
call('bookmarks/update_read_progress', params)
|
85
89
|
end
|
86
90
|
|
87
|
-
def bookmarks_add(
|
88
|
-
call('bookmarks/add',
|
91
|
+
def bookmarks_add(params = {})
|
92
|
+
call('bookmarks/add', params)
|
89
93
|
end
|
90
94
|
|
91
|
-
def bookmarks_delete(
|
92
|
-
call('bookmarks/delete',
|
95
|
+
def bookmarks_delete(params = {})
|
96
|
+
call('bookmarks/delete', params)
|
93
97
|
end
|
94
98
|
|
95
|
-
def bookmarks_star(
|
96
|
-
call('bookmarks/star',
|
99
|
+
def bookmarks_star(params = {})
|
100
|
+
call('bookmarks/star', params)
|
97
101
|
end
|
98
102
|
|
99
|
-
def bookmarks_unstar(
|
100
|
-
call('bookmarks/unstar',
|
103
|
+
def bookmarks_unstar(params = {})
|
104
|
+
call('bookmarks/unstar', params)
|
101
105
|
end
|
102
106
|
|
103
|
-
def bookmarks_archive(
|
104
|
-
call('bookmarks/archive',
|
107
|
+
def bookmarks_archive(params = {})
|
108
|
+
call('bookmarks/archive', params)
|
105
109
|
end
|
106
110
|
|
107
|
-
def bookmarks_unarchive(
|
108
|
-
call('bookmarks/unarchive',
|
111
|
+
def bookmarks_unarchive(params = {})
|
112
|
+
call('bookmarks/unarchive', params)
|
109
113
|
end
|
110
114
|
|
111
|
-
def bookmarks_move(
|
112
|
-
call('bookmarks/move',
|
115
|
+
def bookmarks_move(params = {})
|
116
|
+
call('bookmarks/move', params)
|
113
117
|
end
|
114
118
|
|
115
|
-
def bookmarks_get_text(
|
116
|
-
|
117
|
-
call('bookmarks/get_text', options)
|
119
|
+
def bookmarks_get_text(params = {})
|
120
|
+
call('bookmarks/get_text', params)
|
118
121
|
end
|
119
122
|
|
120
123
|
def folders_list
|
121
124
|
call('folders/list')
|
122
125
|
end
|
123
126
|
|
124
|
-
def folders_add(
|
125
|
-
call('folders/add',
|
127
|
+
def folders_add(params = {})
|
128
|
+
call('folders/add', params)
|
126
129
|
end
|
127
130
|
|
128
|
-
def folders_delete(
|
129
|
-
call('folders/delete',
|
131
|
+
def folders_delete(params = {})
|
132
|
+
call('folders/delete', params)
|
130
133
|
end
|
131
134
|
|
132
|
-
def folders_set_order(
|
133
|
-
call('folders/set_order',
|
135
|
+
def folders_set_order(params = {})
|
136
|
+
call('folders/set_order', params)
|
134
137
|
end
|
135
138
|
end
|
136
139
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
HTTP/1.1 401 Unauthorized
|
2
|
+
Date: Thu, 01 Dec 2011 16:32:47 GMT
|
3
|
+
Server: Apache
|
4
|
+
P3P: CP="ALL ADM DEV PSAi COM OUR OTRo STP IND ONL"
|
5
|
+
X-Robots-Tag: noindex
|
6
|
+
Cache-Control: no-cache
|
7
|
+
Pragma: no-cache
|
8
|
+
X-Powered-By: a lot of coffee and Phish
|
9
|
+
Vary: Accept-Encoding
|
10
|
+
Content-Length: 26
|
11
|
+
Connection: close
|
12
|
+
Content-Type: text/html; charset=UTF-8
|
13
|
+
|
14
|
+
Invalid xAuth credentials.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Date: Thu, 01 Dec 2011 16:31:04 GMT
|
3
|
+
Server: Apache
|
4
|
+
P3P: CP="ALL ADM DEV PSAi COM OUR OTRo STP IND ONL"
|
5
|
+
X-Robots-Tag: noindex
|
6
|
+
Cache-Control: no-cache
|
7
|
+
Pragma: no-cache
|
8
|
+
X-Powered-By: a lot of coffee and Phish
|
9
|
+
Vary: Accept-Encoding
|
10
|
+
Content-Length: 132
|
11
|
+
Connection: close
|
12
|
+
Content-Type: application/x-www-form-urlencoded
|
13
|
+
|
14
|
+
oauth_token=thisisatoken&oauth_token_secret=thisisasecret
|
@@ -0,0 +1,14 @@
|
|
1
|
+
HTTP/1.1 400 Bad Request
|
2
|
+
Date: Thu, 01 Dec 2011 16:43:12 GMT
|
3
|
+
Server: Apache
|
4
|
+
P3P: CP="ALL ADM DEV PSAi COM OUR OTRo STP IND ONL"
|
5
|
+
X-Robots-Tag: noindex
|
6
|
+
Cache-Control: no-cache
|
7
|
+
Pragma: no-cache
|
8
|
+
X-Powered-By: a lot of coffee and Phish
|
9
|
+
Vary: Accept-Encoding
|
10
|
+
Content-Length: 70
|
11
|
+
Connection: close
|
12
|
+
Content-Type: application/json
|
13
|
+
|
14
|
+
[{"type":"error","error_code":1240,"message":"Invalid URL specified"}]
|
@@ -0,0 +1,14 @@
|
|
1
|
+
HTTP/1.1 400 Bad Request
|
2
|
+
Date: Thu, 01 Dec 2011 16:36:08 GMT
|
3
|
+
Server: Apache
|
4
|
+
P3P: CP="ALL ADM DEV PSAi COM OUR OTRo STP IND ONL"
|
5
|
+
X-Robots-Tag: noindex
|
6
|
+
Cache-Control: no-cache
|
7
|
+
Pragma: no-cache
|
8
|
+
X-Powered-By: a lot of coffee and Phish
|
9
|
+
Vary: Accept-Encoding
|
10
|
+
Content-Length: 79
|
11
|
+
Connection: close
|
12
|
+
Content-Type: application/json
|
13
|
+
|
14
|
+
[{"type":"error","error_code":1241,"message":"Invalid or missing bookmark_id"}]
|
@@ -0,0 +1,436 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Date: Thu, 01 Dec 2011 16:35:34 GMT
|
3
|
+
Server: Apache
|
4
|
+
P3P: CP="ALL ADM DEV PSAi COM OUR OTRo STP IND ONL"
|
5
|
+
X-Robots-Tag: noindex
|
6
|
+
Cache-Control: no-cache
|
7
|
+
Pragma: no-cache
|
8
|
+
X-Powered-By: a lot of coffee and Phish
|
9
|
+
Vary: Accept-Encoding
|
10
|
+
Connection: close
|
11
|
+
Transfer-Encoding: chunked
|
12
|
+
Content-Type: text/html; charset=utf-8
|
13
|
+
|
14
|
+
|
15
|
+
<html>
|
16
|
+
<head>
|
17
|
+
<title>Wieden+Kennedy » Why We’re Not Hiring Creative Technologists</title>
|
18
|
+
<meta name="viewport" content="width=device-width; initial-scale=1.0; user-scalable=no; minimum-scale=1.0; maximum-scale=1.0;" />
|
19
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
20
|
+
<meta name="robots" content="noindex"/>
|
21
|
+
<link rel="icon" href="/images/favicon.png"/>
|
22
|
+
<!-- IP:TITLE
|
23
|
+
Wieden+Kennedy » Why We’re Not Hiring Creative Technologists
|
24
|
+
/IP:TITLE -->
|
25
|
+
<!-- IP:IMAGES
|
26
|
+
|
27
|
+
/IP:IMAGES -->
|
28
|
+
<style type="text/css">
|
29
|
+
body {
|
30
|
+
font-family: Georgia;
|
31
|
+
font-size: 16px;
|
32
|
+
margin: 0px auto 0px auto;
|
33
|
+
width: 500px word-wrap: break-word;
|
34
|
+
}
|
35
|
+
|
36
|
+
h1 { font-size: 1.3em; }
|
37
|
+
h2 { font-size: 1.15em; }
|
38
|
+
h3, h4, h5, h6, h7 { font-size: 1.0em; }
|
39
|
+
|
40
|
+
img { border: 0; display: block; margin: 0.5em 0; }
|
41
|
+
pre, code { overflow: scroll; }
|
42
|
+
#story {
|
43
|
+
clear: both; padding: 0 10px; overflow: hidden; margin-bottom: 40px;
|
44
|
+
}
|
45
|
+
|
46
|
+
.bar {
|
47
|
+
color: #555;
|
48
|
+
font-family: 'Helvetica';
|
49
|
+
font-size: 11pt;
|
50
|
+
margin: 0 -20px;
|
51
|
+
padding: 10px 0;
|
52
|
+
}
|
53
|
+
.top { border-bottom: 2px solid #000; }
|
54
|
+
|
55
|
+
.top a {
|
56
|
+
display: block;
|
57
|
+
float: right;
|
58
|
+
text-decoration: none;
|
59
|
+
font-size: 11px;
|
60
|
+
background-color: #eee;
|
61
|
+
-webkit-border-radius: 8px;
|
62
|
+
-moz-border-radius: 8px;
|
63
|
+
padding: 2px 15px;
|
64
|
+
}
|
65
|
+
|
66
|
+
#story div {
|
67
|
+
margin: 1em 0;
|
68
|
+
}
|
69
|
+
|
70
|
+
.bottom {
|
71
|
+
border-top: 2px solid #000;
|
72
|
+
color: #555;
|
73
|
+
}
|
74
|
+
|
75
|
+
.bar a { color: #444; }
|
76
|
+
|
77
|
+
blockquote {
|
78
|
+
border-top: 1px solid #bbb;
|
79
|
+
border-bottom: 1px solid #bbb;
|
80
|
+
margin: 1.5em 0;
|
81
|
+
padding: 0.5em 0;
|
82
|
+
}
|
83
|
+
blockquote.short { font-style: italic; }
|
84
|
+
|
85
|
+
pre {
|
86
|
+
white-space: pre-wrap;
|
87
|
+
}
|
88
|
+
|
89
|
+
ul.bodytext, ol.bodytext {
|
90
|
+
list-style: none;
|
91
|
+
margin-left: 0;
|
92
|
+
padding-left: 0em;
|
93
|
+
}
|
94
|
+
|
95
|
+
</style>
|
96
|
+
</head>
|
97
|
+
<body onload="loadFont();">
|
98
|
+
<div class="bar top">
|
99
|
+
<a href="http://blog.wk.com/2011/10/21/why-we-are-not-hiring-creative-technologists/">View original</a>
|
100
|
+
<div class="sm">blog.wk.com</div>
|
101
|
+
</div>
|
102
|
+
|
103
|
+
<div id="editing_controls" style="float: right; padding-top: 2px;">
|
104
|
+
</div>
|
105
|
+
|
106
|
+
<div id="story">
|
107
|
+
<div>
|
108
|
+
<h1><a href="http://blog.wk.com/2011/10/21/why-we-are-not-hiring-creative-technologists/" rel="bookmark" title="Permanent Link to Why We’re Not Hiring Creative Technologists">
|
109
|
+
Why We’re Not Hiring Creative Technologists</a></h1>
|
110
|
+
<p><a href="http://blog.wk.com/2011/10/20/why-we%E2%80%99re-not-hiring-creative-technologists">
|
111
|
+
<img title="102011programming" src="http://blog.wk.com/wordpress/wp-content/uploads/2011/10/102011programming.jpg" alt="" /></a></p>
|
112
|
+
<p>In the digital, interactive and social media-focused agency
|
113
|
+
world, it’s easy to talk a big game, but for disciplines that
|
114
|
+
require true, deep knowledge of the subject for success,
|
115
|
+
there’s a fine line between “understanding” and
|
116
|
+
“expertise”. Our Creative Technology Director Igor
|
117
|
+
Clark explains why ideas aren’t enough, below the jump.</p>
|
118
|
+
<p><br />
|
119
|
+
By Igor Clark, Creative Technology Director</p>
|
120
|
+
<p>I’ve pretty much had it with the term “Creative
|
121
|
+
Technology”. I’m a “Creative Technology
|
122
|
+
Director” myself, and even I’m over it: already it
|
123
|
+
seems clichéd at best, and at worst, bordering on the
|
124
|
+
meaningless. Here’s why.</p>
|
125
|
+
<p>Not so long ago, the rise and rise of “digital”
|
126
|
+
meant agencies having to come up with increasing amounts of
|
127
|
+
interactive work. They didn’t know how to do it, so their
|
128
|
+
developers got screwed, and the work suffered. Horribly.</p>
|
129
|
+
<p>Few outside the tech teams grasped what was involved in building
|
130
|
+
the software needed for digital campaigns. Crazy deadlines,
|
131
|
+
unrealistic expectations, ill-considered and even ill-advised
|
132
|
+
requirements led to ever-more “inventive” technical
|
133
|
+
solutions. Then, when the last-minute hack they had to cobble
|
134
|
+
together failed to stand up to the traffic they never promised it
|
135
|
+
would, developers were cursed and vilified.</p>
|
136
|
+
<p>But this wasn’t the really bad part. Software folk who
|
137
|
+
found their way into agency-land either loved it, and stayed
|
138
|
+
– or they didn’t, and left. For the ones who stuck
|
139
|
+
around, and who felt the pain most acutely, the really bad part
|
140
|
+
wasn’t the pressure or the deadlines: it was that their work
|
141
|
+
wasn’t understood, so it wasn’t properly
|
142
|
+
recognized.</p>
|
143
|
+
<p>Their work wasn’t purely science or technology; though
|
144
|
+
grounded in both, it was far from the simple application of
|
145
|
+
formulae or solving of equations. Developers knew that you
|
146
|
+
couldn’t take a creative brief as a set of instructions and
|
147
|
+
just “translate” it into software. You have to
|
148
|
+
interpret it, and that takes an extra spark. A creative spark. They
|
149
|
+
saw this was a fundamental part of the overall interactive creative
|
150
|
+
process, and yet a parallel, creative process of its own. The
|
151
|
+
naming perpetuated the misunderstanding, and so it had to
|
152
|
+
change.</p>
|
153
|
+
<p>At the same time, people across agencies were recognizing that
|
154
|
+
their existing creative model just wasn’t working out for
|
155
|
+
“interactive”. Crews outside the fortress walls were
|
156
|
+
doing innovative and engaging work, not only through using new and
|
157
|
+
different technologies to do it (openFrameworks, Processing, robots
|
158
|
+
and Arduino, computer vision & Kinect, projection mapping, the
|
159
|
+
list goes on), but also by trying out different approaches and
|
160
|
+
processes. Namely: the technology was the creative.</p>
|
161
|
+
<p><img title="102011kinect" src="http://blog.wk.com/wordpress/wp-content/uploads/2011/10/102011kinect.jpg" alt="" /></p>
|
162
|
+
<p><em><small>Photo by <a href="http://www.flickr.com/photos/maveric2003/5810664761/sizes/z/in/photostream/">
|
163
|
+
maveric2003</a>, licensed under the <a href="http://creativecommons.org/licenses/by/2.0/">Creative
|
164
|
+
Commons</a></small></em></p>
|
165
|
+
<p>In this way, “creative technology” was born: partly
|
166
|
+
to assuage the accumulating angst of downtrodden developers; partly
|
167
|
+
to enable those developers willing to step up to the creative plate
|
168
|
+
also to step outside the conventional development toolkit; and
|
169
|
+
partly – perhaps most importantly – to spread awareness
|
170
|
+
across the board that where interactive work is concerned, creating
|
171
|
+
involves making; making interactive stuff involves technology; and
|
172
|
+
people can be creative in a range of disciplines, not only blue-sky
|
173
|
+
ideation.</p>
|
174
|
+
<p>At its inception, this was A Good Thing, and it happened for
|
175
|
+
Good Reasons. So what happened? Why do I now find myself wondering
|
176
|
+
whether Creative Technology, as a label and a discipline, is
|
177
|
+
effectively bankrupt?</p>
|
178
|
+
<p>As in any new, burgeoning and (to many) incomprehensible field,
|
179
|
+
most people have neither the background nor the time to get under
|
180
|
+
the surface and really understand what it’s all about. So
|
181
|
+
they need people to help do that.</p>
|
182
|
+
<p>Unfortunately, in any field requiring background and time to get
|
183
|
+
beneath the surface, the ninja dust is easy to throw in the faces
|
184
|
+
of the uninitiated, disguising the underlying truth – which
|
185
|
+
is, all too frequently, only a surface-level familiarity with the
|
186
|
+
necessary materials.</p>
|
187
|
+
<p>University and training courses spring up, servicing the new
|
188
|
+
market of people wanting to get educated in the new field. Courses
|
189
|
+
need funding; funding requires admissions; admissions policies get
|
190
|
+
broadened; broad admissions policies welcome novices and amateurs.
|
191
|
+
Ergo, disciplines become ill-disciplined, specialization becomes
|
192
|
+
flabby and watered-down to the point of meaninglessness.</p>
|
193
|
+
<p>Outcome: “creative technologists” who think that
|
194
|
+
their daily use of social media, “passion for digital”
|
195
|
+
and pile of half-baked ideas about QR codes, mobile integration and
|
196
|
+
Facebook apps constitute an entitlement to have those ideas brought
|
197
|
+
to life by the still-downtrodden developers, still languishing in
|
198
|
+
the dungeons of overworked production companies and in-house
|
199
|
+
development teams.</p>
|
200
|
+
<p><img title="102011code2" src="http://blog.wk.com/wordpress/wp-content/uploads/2011/10/102011code2.jpg" alt="" /></p>
|
201
|
+
<p><em><small>Photo by <a href="http://twitter.com/igorclark/">Igor
|
202
|
+
Clark</a></small></em></p>
|
203
|
+
<p>As a result, “Creative Technology” has become
|
204
|
+
watered down to the point where people fresh out of “creative
|
205
|
+
tech” courses need only sprinkle some of that digital
|
206
|
+
ninja-dust on their resumés, and those without the requisite
|
207
|
+
background, know-how and experience to sort the wheat from the
|
208
|
+
chaff are none the wiser.</p>
|
209
|
+
<p>The talent drifts off. The ninjas plan and conceive the work,
|
210
|
+
and analyse its success, using metrics no-one else understands. Bad
|
211
|
+
work proliferates, becomes accepted and normalized within the
|
212
|
+
industry; the really good people get further alienated, more dust
|
213
|
+
is thrown to disguise others taking their places, and round and
|
214
|
+
round it goes, until no-one knows who’s a ninja and
|
215
|
+
who’s not. Except for the best people, who’ve left the
|
216
|
+
agency scene in the dust – and the audience, of course, who
|
217
|
+
are left unmoved. Or, worse, switched off.</p>
|
218
|
+
<p>Is this pattern inevitable? Can we, as agency-land
|
219
|
+
technologists, do anything about it?</p>
|
220
|
+
<p>Clearly many non-technical factors are involved, but there is
|
221
|
+
one simple and concrete thing we can do: stop hiring
|
222
|
+
“creative technologists”. Hire coders. Reject
|
223
|
+
compromise on this front, and resist pressure to give in to it.
|
224
|
+
Only hire people to work at the crossover of creative and
|
225
|
+
technology if they have strong, practical, current coding
|
226
|
+
skills.</p>
|
227
|
+
<p>Don’t fall for the illusion that a candidate is creatively
|
228
|
+
strong enough to compensate for the weak code. Spending a year or
|
229
|
+
two on a training course gaining a passing acquaintance with a
|
230
|
+
couple of trending technologies isn’t good enough. They need
|
231
|
+
to live and breathe this stuff, and to use the appropriate
|
232
|
+
languages and tools fluently and transparently, without stopping to
|
233
|
+
think about it. So if a person puts “creative
|
234
|
+
technologist” on their resumé, but doesn’t know
|
235
|
+
how to code, can’t show you things they’ve made, and
|
236
|
+
can’t prove they made them by explaining why they wrote the
|
237
|
+
code the way they did, don’t hire them. Simple as that.</p>
|
238
|
+
<p>Think this sounds elitist? Well, it is – and there’s
|
239
|
+
a reason.</p>
|
240
|
+
<p><img title="102011pages" src="http://blog.wk.com/wordpress/wp-content/uploads/2011/10/102011pages.jpg" alt="" /></p>
|
241
|
+
<p><em><small>Photo by <a href="http://twitter.com/igorclark/">Igor
|
242
|
+
Clark</a></small></em></p>
|
243
|
+
<p>Agencies don’t hire writers just because they know the
|
244
|
+
rules of grammar. We hire them because they’re eloquent,
|
245
|
+
lucid, imaginative wordsmiths. We hire them because of their
|
246
|
+
practised ability to lovingly craft words into things that work.
|
247
|
+
Things that make people feel.</p>
|
248
|
+
<p>There are people who engineer excellent software. There are
|
249
|
+
people who come up with amazing ideas. The interactive space by
|
250
|
+
definition requires the fusion of the two, and technology at the
|
251
|
+
heart of creation. At the point of intersection, you’re going
|
252
|
+
to need people who understand both, and who have one foot on either
|
253
|
+
side. As Forrester’s Mike Gualtieri recently wrote in
|
254
|
+
<a href="http://blogs.forrester.com/mike_gualtieri/11-10-12-agile_software_is_a_cop_out_heres_whats_next">
|
255
|
+
a fresh piece about how to create great software</a>, that means
|
256
|
+
“renaissance developers who have passion, creativity,
|
257
|
+
discipline, domain knowledge, and user empathy”.</p>
|
258
|
+
<p>This is difficult territory for creative agencies. Maybe you
|
259
|
+
don’t know how to hire these people yet. Maybe it
|
260
|
+
doesn’t fit with your structures. Tough, isn’t it? But
|
261
|
+
you’re going to have to deal with it, and fix it.</p>
|
262
|
+
<p>Ultimately, to do that you need to provide an environment
|
263
|
+
that’s as appealing and satisfying for extraordinary,
|
264
|
+
creative software people as the one you already provide is for
|
265
|
+
traditional creative folks. But it also needs to be as appealing to
|
266
|
+
this new breed as their potential alternate settings at Google,
|
267
|
+
Facebook, Tech Startup X. Fortunately, you have the potential to
|
268
|
+
make it even more so for genuine creative coders – because
|
269
|
+
they’re not looking for pure engineering any more than you
|
270
|
+
are.</p>
|
271
|
+
<p>While you don’t need to become an engineering company, you
|
272
|
+
face some of their challenges. You need to understand, accept and
|
273
|
+
embrace some of the nuts and bolts of software development, and
|
274
|
+
take on board the work dedicated shops are doing on its processes.
|
275
|
+
You need such a strong streak of code running through the
|
276
|
+
atmosphere that coders want to come to you, and everyone else gets
|
277
|
+
code spilling over them.</p>
|
278
|
+
<p>But “digital” is a hybrid realm, and you need to
|
279
|
+
provide a balance. Fortunately, you’re in a perfect position
|
280
|
+
to counterpoint the engineering-first environment that others have
|
281
|
+
so successfully developed, leading so successfully to technically
|
282
|
+
excellent, efficient, and often creatively uninspiring work. You
|
283
|
+
have the creative angle covered (right?), so to get to the hybrid
|
284
|
+
middle-ground, you have to allow developers the flexibility, the
|
285
|
+
leeway and the time to engineer solid work – and you have to
|
286
|
+
welcome the hybrid creative coders into the heart of what you do,
|
287
|
+
to make a hybrid place where they feel at home, and where they can
|
288
|
+
help ensure that what gets sold makes sense, and that it can be
|
289
|
+
made without actually killing a team of engineers in the
|
290
|
+
attempt.</p>
|
291
|
+
<p><img title="102011comment" src="http://blog.wk.com/wordpress/wp-content/uploads/2011/10/102011comment.jpg" alt="" /></p>
|
292
|
+
<p><em><small>Photo by <a href="http://twitter.com/igorclark/">Igor
|
293
|
+
Clark</a></small></em></p>
|
294
|
+
<p>Don’t get me wrong, this is hard, and it’ll take
|
295
|
+
time. It’s not just procedural, but cultural, so a big part
|
296
|
+
of doing it comes down to who you hire and how you let them do
|
297
|
+
their thing. But that’s exactly the point. That’s why
|
298
|
+
it’s most important, way before you get all that fixed, and
|
299
|
+
as the first major step on that road: just don’t hire
|
300
|
+
“creative technologists” who aren’t strong
|
301
|
+
coders.</p>
|
302
|
+
<p>Bottom line, these people need to make stuff, fast. They need to
|
303
|
+
prove or disprove concepts, in ways that non-technologists
|
304
|
+
understand, fast. So they need to know how to code efficiently,
|
305
|
+
economically and effectively. They need to understand the
|
306
|
+
appropriate technology stack from top to bottom, know which tools
|
307
|
+
are right for the job – and most of all, they must be
|
308
|
+
prepared to crack their knuckles, roll up their sleeves and get
|
309
|
+
their fingers into the code. Up to the elbows.</p>
|
310
|
+
<p>You’re probably thinking, “OK, those people are few
|
311
|
+
and far between; we still need people to bridge the gap between
|
312
|
+
them and the rest of the agency”. You’re not wrong;
|
313
|
+
you’ve put your finger straight on the really interesting
|
314
|
+
corollary, and the exact reason why creative agencies could be the
|
315
|
+
most inspiring environment for creative coders, which is simply
|
316
|
+
this: we have to be.</p>
|
317
|
+
<p>With integrated interactive work ever more critical, creative
|
318
|
+
agencies need to change drastically, in ways that suit perfectly
|
319
|
+
those people we most need to attract. We need to adapt and evolve
|
320
|
+
to survive. The serious talent is doing it for itself; going to
|
321
|
+
small shops, shooting solo. To reach the very best people, we need
|
322
|
+
to change in ways that make them want to come to us; to allow and
|
323
|
+
even help them to change us, and to help us shape our
|
324
|
+
evolution.</p>
|
325
|
+
<p><img title="102011code1" src="http://blog.wk.com/wordpress/wp-content/uploads/2011/10/102011code1.jpg" alt="" /></p>
|
326
|
+
<p><em><small>Photo by <a href="http://twitter.com/igorclark/">Igor
|
327
|
+
Clark</a></small></em></p>
|
328
|
+
<p>This is more than “building a digital team”, or
|
329
|
+
“covering digital bases”. The agency as a whole has to
|
330
|
+
step up to the tectonic plate and realize that not only are
|
331
|
+
digital, social, interactive, gaming all here to stay, but they
|
332
|
+
already permeate the entire landscape of what consumers are doing.
|
333
|
+
We need to change our processes, structures and approach to how we
|
334
|
+
create in order to accommodate this stuff, and open our arms to the
|
335
|
+
people who make it happen.</p>
|
336
|
+
<p>Start off by refusing to believe people who tell you that hiring
|
337
|
+
them to do the understanding for you means you can carry on as you
|
338
|
+
were. Instead, hire the right people in the right places, and make
|
339
|
+
the changes necessary to let them do what they do. Creative people
|
340
|
+
who can code up a storm, and, critically, experienced people who
|
341
|
+
can properly assess the code they’re shown. These are the
|
342
|
+
people who will help us flourish – if we can help them to do
|
343
|
+
the same.</p>
|
344
|
+
<p>At W+K we’re always looking to meet good technology
|
345
|
+
people, and we want to read your code. Developers, engineers,
|
346
|
+
creative coders. If that’s you, if you’ve got the
|
347
|
+
endurance to make it this far, and if you’re interested in
|
348
|
+
applying your creativity through code with us in Portland, then why
|
349
|
+
not <a href="http://www.wk.com/jobs/portland/technology">get in
|
350
|
+
touch</a>?</p>
|
351
|
+
<p>Find Igor on Twitter at <a href="http://twitter.com/igorclark">@IgorClark</a>.</p>
|
352
|
+
<p>Posted on 10.21.11</p>
|
353
|
+
<div>
|
354
|
+
<p>Category: <a href="http://blog.wk.com/category/guest-post/" title="View all posts in Guest Post" rel="category tag">Guest
|
355
|
+
Post</a>, <a href="http://blog.wk.com/category/interactive/" title="View all posts in Interactive" rel="category tag">Interactive</a></p>
|
356
|
+
</div>
|
357
|
+
<p><a href="http://blog.wk.com/2011/10/17/wk-12-7-class-graduates-celebrates/" rel="prev">« Older Post</a></p>
|
358
|
+
<div>
|
359
|
+
<h2>Features</h2>
|
360
|
+
<div>
|
361
|
+
<ul class="bodytext"><li><a href="http://blog.wk.com/2011/09/20/dan-wieden-honored-with-catalyst-award-at-2011-adcolor-awards/">
|
362
|
+
<img src="http://blog.wk.com/wordpress/wp-content/uploads/2011/09/092011danadcolor-310x139.jpg" alt="092011danadcolor" title="092011danadcolor" /></a>
|
363
|
+
<h3><a href="http://blog.wk.com/2011/09/20/dan-wieden-honored-with-catalyst-award-at-2011-adcolor-awards/">
|
364
|
+
Dan Wieden Honored with Catalyst Award at 2011 Adcolor
|
365
|
+
Awards</a></h3>
|
366
|
+
<p>This week, our own Dan Wieden was honored with the Catalyst
|
367
|
+
award at the 2011 Adcolor Awards ceremony in Los Angeles. Dan has
|
368
|
+
always been committed to making the voice and people of advertising
|
369
|
+
and specifically W+K more diverse. Our diversity and inclusion
|
370
|
+
manager Porsha Monroe has shared some thoughts with us.</p>
|
371
|
+
<a href="http://blog.wk.com/2011/09/20/dan-wieden-honored-with-catalyst-award-at-2011-adcolor-awards/">Read
|
372
|
+
More…</a></li>
|
373
|
+
<li><a href="http://blog.wk.com/2011/09/07/wk-community-mayor-sam-adams-celebrate-first-thursday-portland-incubator-experiment-pie-ribbon-cutting/">
|
374
|
+
<img src="http://blog.wk.com/wordpress/wp-content/uploads/2011/09/090711piemain-310x139.jpg" alt="090711piemain" title="090711piemain" /></a>
|
375
|
+
<h3><a href="http://blog.wk.com/2011/09/07/wk-community-mayor-sam-adams-celebrate-first-thursday-portland-incubator-experiment-pie-ribbon-cutting/">
|
376
|
+
W+K Community & Mayor Sam Adams Celebrate First Thursday
|
377
|
+
Portland Incubator Experiment (PIE) Ribbon-Cutting</a></h3>
|
378
|
+
<p>Members of Wieden+Kennedy, the Portland tech community, Mayor
|
379
|
+
Sam Adams and our friends and associates gathered together for last
|
380
|
+
week’s <a href="http://www.firstthursdayportland.com/">First
|
381
|
+
Thursday</a> to celebrate the official ribbon cutting ceremony for
|
382
|
+
the <a href="http://piepdx.com">Portland Incubator Experiment</a>
|
383
|
+
(more commonly known as PIE), a collaborative center that partners
|
384
|
+
leading brands with technology innovators to cultivate community,
|
385
|
+
entrepreneurship and creative thinking.</p>
|
386
|
+
<a href="http://blog.wk.com/2011/09/07/wk-community-mayor-sam-adams-celebrate-first-thursday-portland-incubator-experiment-pie-ribbon-cutting/">Read
|
387
|
+
More…</a></li>
|
388
|
+
<li><a href="http://blog.wk.com/2011/08/29/musician-and-comic-book-artist-daniel-johnston-concludes-space-ducks-art-show-with-concert-performance-in-wk-foyer/">
|
389
|
+
<img src="http://blog.wk.com/wordpress/wp-content/uploads/2011/08/082911djmain-310x139.jpg" alt="082911djmain" title="082911djmain" /></a>
|
390
|
+
<h3><a href="http://blog.wk.com/2011/08/29/musician-and-comic-book-artist-daniel-johnston-concludes-space-ducks-art-show-with-concert-performance-in-wk-foyer/">
|
391
|
+
Musician & Comic Artist Daniel Johnston Concludes <em>Space
|
392
|
+
Ducks</em> Art Show with Concert Performance in W+K Foyer</a></h3>
|
393
|
+
<p>On Thursday, the month-long show of Daniel Johnston’s
|
394
|
+
Space Ducks: An Infinite Comic Book of Musical Greatness concluded
|
395
|
+
with a performance by the man himself. The event coincided with the
|
396
|
+
relaunch of his site, http://hihowareyou.com, produced in
|
397
|
+
partnership with W+K and WKE.</p>
|
398
|
+
<a href="http://blog.wk.com/2011/08/29/musician-and-comic-book-artist-daniel-johnston-concludes-space-ducks-art-show-with-concert-performance-in-wk-foyer/">Read
|
399
|
+
More…</a></li>
|
400
|
+
</ul></div>
|
401
|
+
</div>
|
402
|
+
<div>
|
403
|
+
<h2>Goodness</h2>
|
404
|
+
<div>
|
405
|
+
<ul class="bodytext"><li><a href="http://wkstudio.bigcartel.com/product/deep-down-inside-we-all-love-math-t-shirt">
|
406
|
+
<img src="http://blog.wk.com/wordpress/wp-content/files_mf/math_shirt.jpg" alt="image" /></a>
|
407
|
+
<h3><a href="http://wkstudio.bigcartel.com/product/deep-down-inside-we-all-love-math-t-shirt">
|
408
|
+
We All Love Math T-shirt</a></h3>
|
409
|
+
<p>If this shirt + its thesis succeed, we will all revel in our
|
410
|
+
essential mathness.</p>
|
411
|
+
</li>
|
412
|
+
<li><a href="http://wkstudio.bigcartel.com/product/graphics-design-t-shirt"><img src="http://blog.wk.com/wordpress/wp-content/files_mf/graphicshirt.jpg" alt="image" /></a>
|
413
|
+
<h3><a href="http://wkstudio.bigcartel.com/product/graphics-design-t-shirt">Graphics
|
414
|
+
Design™ T-shirt</a></h3>
|
415
|
+
<p>The soul-wrenching existential crisis many commercial artists
|
416
|
+
struggle with…</p>
|
417
|
+
</li>
|
418
|
+
<li><a href="http://wkstudio.bigcartel.com/product/teen-baby-onesie"><img src="http://blog.wk.com/wordpress/wp-content/files_mf/babyshirt.jpg" alt="image" /></a>
|
419
|
+
<h3><a href="http://wkstudio.bigcartel.com/product/teen-baby-onesie">Modern
|
420
|
+
Baby Onesie</a></h3>
|
421
|
+
<p>You are observing a genuine onesie that… Oh, man. That
|
422
|
+
baby’s such a dick.</p>
|
423
|
+
</li>
|
424
|
+
</ul><p><a href="http://wkstudio.bigcartel.com/">See more at the
|
425
|
+
Goodness Store.</a></p>
|
426
|
+
</div>
|
427
|
+
</div>
|
428
|
+
|
429
|
+
|
430
|
+
|
431
|
+
</div></div>
|
432
|
+
|
433
|
+
<div class="bar bottom">
|
434
|
+
</div>
|
435
|
+
</body>
|
436
|
+
</html>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Date: Thu, 01 Dec 2011 16:33:47 GMT
|
3
|
+
Server: Apache
|
4
|
+
P3P: CP="ALL ADM DEV PSAi COM OUR OTRo STP IND ONL"
|
5
|
+
X-Robots-Tag: noindex
|
6
|
+
Cache-Control: no-cache
|
7
|
+
Pragma: no-cache
|
8
|
+
X-Powered-By: a lot of coffee and Phish
|
9
|
+
Vary: Accept-Encoding
|
10
|
+
Connection: close
|
11
|
+
Transfer-Encoding: chunked
|
12
|
+
Content-Type: application/json
|
13
|
+
|
14
|
+
[{"type":"meta"},{"type":"user","user_id":140230,"username":"tom@tomtaylor.co.uk","subscription_is_active":"1"},{"type":"bookmark","bookmark_id":222945036,"url":"http:\/\/joemoransblog.blogspot.com\/2011\/11\/quiet-pleas.html","title":"Quiet pleas","description":"","time":1321217383,"starred":"0","private_source":"","hash":"cSyver1h","progress":"0","progress_timestamp":1321222208},{"type":"bookmark","bookmark_id":222697290,"url":"http:\/\/potlatch.typepad.com\/weblog\/2011\/11\/poppies-as-national-cultural-audit.html","title":"poppies as national cultural audit","description":"","time":1321119220,"starred":"0","private_source":"","hash":"n7Ic8ADA","progress":"0","progress_timestamp":1321212733},{"type":"bookmark","bookmark_id":222036793,"url":"http:\/\/dashes.com\/anil\/2011\/11\/how-the-99-and-the-tea-party-can-occupy-whitehousegov.html","title":"How the 99% and the Tea Party can Occupy WhiteHouse.gov","description":"","time":1320919525,"starred":"0","private_source":"","hash":"4PGtE6DR","progress":"0","progress_timestamp":1321099791},{"type":"bookmark","bookmark_id":221679923,"url":"http:\/\/blog.pinboard.in\/2011\/11\/the_social_graph_is_neither\/","title":"The Social Graph is Neither","description":"","time":1320825317,"starred":"0","private_source":"","hash":"JlTb3HiL","progress":"0","progress_timestamp":1321099791},{"type":"bookmark","bookmark_id":221194670,"url":"http:\/\/potlatch.typepad.com\/weblog\/2011\/11\/the-post-speculative-olympics.html","title":"the post-speculative Olympics","description":"","time":1320700650,"starred":"0","private_source":"","hash":"JY4hOv1h","progress":"0.655525","progress_timestamp":1322300394},{"type":"bookmark","bookmark_id":221193800,"url":"http:\/\/www.vanityfair.com\/hollywood\/features\/2011\/12\/david-fincher-201112","title":"V.F. Portrait: David Fincher | Hollywood | Vanity Fair","description":"","time":1320700460,"starred":"0","private_source":"","hash":"TQWRqpPd","progress":"0.694745","progress_timestamp":1321431332},{"type":"bookmark","bookmark_id":220538037,"url":"http:\/\/nymag.com\/print\/?\/news\/media\/elisabeth-murdoch-2011-11\/","title":"Elisabeth of the Murdochs","description":"","time":1320483738,"starred":"0","private_source":"","hash":"7EnvQLNi","progress":"0","progress_timestamp":1320613297},{"type":"bookmark","bookmark_id":220537972,"url":"http:\/\/www.vanityfair.com\/business\/features\/2011\/12\/murdoch-kids-201112.print","title":"The Rules of Succession | Business | Vanity Fair","description":"","time":1320483700,"starred":"0","private_source":"","hash":"LR7xzrgT","progress":"0","progress_timestamp":1320613300},{"type":"bookmark","bookmark_id":219761486,"url":"http:\/\/www.theparisreview.org\/interviews\/6089\/the-art-of-fiction-no-211-william-gibson","title":"Paris Review - The Art of Fiction No. 211, William Gibson","description":"","time":1320262786,"starred":"0","private_source":"","hash":"2zPjDydh","progress":"0.721902","progress_timestamp":1320597912},{"type":"bookmark","bookmark_id":218916491,"url":"http:\/\/www.bbc.co.uk\/blogs\/adamcurtis\/2011\/10\/dream_on.html","title":"DREAM ON","description":"","time":1320044972,"starred":"0","private_source":"","hash":"g6KlbVIC","progress":"0","progress_timestamp":1320309552},{"type":"bookmark","bookmark_id":202971816,"url":"http:\/\/www.wired.com\/wired\/archive\/4.12\/ffglass_pr.html","title":"4.12: Mother Earth Mother Board","description":"","time":1319928054,"starred":"0","private_source":"","hash":"ZguEiZ00","progress":"0.0743572","progress_timestamp":1321227679},{"type":"bookmark","bookmark_id":217988594,"url":"http:\/\/www.monbiot.com\/2011\/10\/27\/its-the-rich-wot-gets-the-pleasure\/","title":"It\u2019s the Rich Wot Gets the Pleasure","description":"","time":1319742534,"starred":"0","private_source":"","hash":"KjYD4hen","progress":"0","progress_timestamp":1319961988},{"type":"bookmark","bookmark_id":217124108,"url":"http:\/\/economicsintelligence.com\/2011\/03\/11\/the-economics-of-bike-lanes-%E2%80%93-how-can-john-cassidy-get-it-so-wrong\/","title":"The Economics of Bike Lanes \u2013 How can John Cassidy get it so wrong? | Economics Intelligence","description":"","time":1319535770,"starred":"0","private_source":"","hash":"hPpLAMzZ","progress":"0","progress_timestamp":1319961991},{"type":"bookmark","bookmark_id":216402077,"url":"http:\/\/theeuropean-magazine.com\/352-dyson-george\/353-evolution-and-innovation","title":"George Dyson | Evolution and Innovation - Information Is Cheap, Meaning Is Expensive | The European Magazine","description":"","time":1319326029,"starred":"0","private_source":"","hash":"jfzPj89D","progress":"0","progress_timestamp":1319534414},{"type":"bookmark","bookmark_id":216295911,"url":"http:\/\/www.antipope.org\/charlie\/blog-static\/2011\/10\/a-cultural-experiment.html","title":"A cultural thought experiment","description":"","time":1319294676,"starred":"0","private_source":"","hash":"S9RqWztN","progress":"0","progress_timestamp":1319534424},{"type":"bookmark","bookmark_id":216141787,"url":"http:\/\/blog.wk.com\/2011\/10\/21\/why-we-are-not-hiring-creative-technologists\/","title":"Wieden+Kennedy \u00bb Why We\u2019re Not Hiring Creative Technologists","description":"","time":1319235364,"starred":"0","private_source":"","hash":"mWKHh9eT","progress":"0","progress_timestamp":1319534425},{"type":"bookmark","bookmark_id":215927373,"url":"http:\/\/earlyretirementextreme.com\/how-i-live-on-7000-per-year.html","title":"\u00bb How I live on $7,000 per year Early Retirement Extreme: \u2014 The choice nobody ever told you about","description":"","time":1319181501,"starred":"0","private_source":"","hash":"DuQSUQ5U","progress":"0","progress_timestamp":1319534436},{"type":"bookmark","bookmark_id":215927355,"url":"http:\/\/earlyretirementextreme.com\/peak-oil-next-kondratiev-cycle-turningsand-ere.html","title":"\u00bb Peak oil, the next Kondratiev cycle, generational turnings, and ERE Early Retirement Extreme: \u2014 The choice nobody ever told you about","description":"","time":1319181495,"starred":"0","private_source":"","hash":"V4tGRMj7","progress":"0","progress_timestamp":1319534438},{"type":"bookmark","bookmark_id":215927269,"url":"http:\/\/www.economist.com\/node\/21533400","title":"Capitalism and its critics: Rage against the machine | The Economist","description":"","time":1319181457,"starred":"0","private_source":"","hash":"tk3W7aXn","progress":"0","progress_timestamp":1319534439},{"type":"bookmark","bookmark_id":215201984,"url":"http:\/\/online.wsj.com\/article\/SB10001424052970203914304576627252381486880.html?mod=WSJ_hps_editorsPicks_1","title":"A Future for Pay Phones? - WSJ.com","description":"","time":1319006861,"starred":"0","private_source":"","hash":"BY3la9rz","progress":"0","progress_timestamp":1319007125},{"type":"bookmark","bookmark_id":214644989,"url":"http:\/\/www.monbiot.com\/2011\/10\/17\/show-me-the-money\/","title":"George Monbiot \u2013 Show Me The Money","description":"","time":1318881511,"starred":"0","private_source":"","hash":"aYYsaIpT","progress":"0","progress_timestamp":1319007128},{"type":"bookmark","bookmark_id":213000484,"url":"http:\/\/caravanmagazine.in\/Story.aspx?StoryId=1095","title":"Mind the Gap","description":"","time":1318400657,"starred":"0","private_source":"","hash":"AGxX4SrJ","progress":"0","progress_timestamp":1318521885},{"type":"bookmark","bookmark_id":213000080,"url":"http:\/\/code.flickr.com\/blog\/2011\/10\/11\/talk-real-time-updates-on-the-cheap-for-fun-and-profit\/","title":"Talk: Real-time Updates on the Cheap for Fun and Profit","description":"","time":1318400552,"starred":"0","private_source":"","hash":"lXv7Dujf","progress":"0","progress_timestamp":1318521895},{"type":"bookmark","bookmark_id":212091573,"url":"http:\/\/www.guardian.co.uk\/world\/2011\/oct\/08\/amanda-knox-facial-expressions","title":"Amanda Knox: What's in a face? | World news | The Guardian","description":"","time":1318148366,"starred":"0","private_source":"","hash":"LJ0N8IeG","progress":"0","progress_timestamp":1318521896},{"type":"bookmark","bookmark_id":211853230,"url":"http:\/\/www.engineyard.com\/podcast\/s01e43-chris-nelson","title":"Ruby Cloud | Ruby Support | Engine Yard","description":"","time":1318058840,"starred":"0","private_source":"","hash":"Js779Psg","progress":"0","progress_timestamp":1318521902}]
|
@@ -0,0 +1,14 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Date: Thu, 01 Dec 2011 16:31:05 GMT
|
3
|
+
Server: Apache
|
4
|
+
P3P: CP="ALL ADM DEV PSAi COM OUR OTRo STP IND ONL"
|
5
|
+
X-Robots-Tag: noindex
|
6
|
+
Cache-Control: no-cache
|
7
|
+
Pragma: no-cache
|
8
|
+
X-Powered-By: a lot of coffee and Phish
|
9
|
+
Vary: Accept-Encoding
|
10
|
+
Content-Length: 96
|
11
|
+
Connection: close
|
12
|
+
Content-Type: application/json
|
13
|
+
|
14
|
+
[{"type":"user","user_id":140230,"username":"tom@tomtaylor.co.uk","subscription_is_active":"1"}]
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
+
|
3
|
+
class InstapaperAPITest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include AssetHelpers
|
6
|
+
|
7
|
+
def stub_successful_authentication
|
8
|
+
stub_request(:post, "https://www.instapaper.com/api/1/oauth/access_token").to_return(
|
9
|
+
http_response('access_token_success')
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
def stub_failed_authentication
|
14
|
+
stub_request(:post, "https://www.instapaper.com/api/1/oauth/access_token").to_return(
|
15
|
+
http_response('access_token_failure')
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def stub_successful_verify_credentials
|
20
|
+
stub_request(:post, "https://www.instapaper.com/api/1/account/verify_credentials").to_return(
|
21
|
+
http_response('verify_credentials_success')
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def stub_successful_bookmarks_list
|
26
|
+
stub_request(:post, "https://www.instapaper.com/api/1/bookmarks/list").to_return(
|
27
|
+
http_response('bookmarks_list_success')
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def stub_failed_bookmarks_add
|
32
|
+
stub_request(:post, "https://www.instapaper.com/api/1/bookmarks/add").to_return(
|
33
|
+
http_response('bookmarks_add_failure')
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
def stub_successful_bookmarks_get_text
|
38
|
+
stub_request(:post, "https://www.instapaper.com/api/1/bookmarks/get_text").
|
39
|
+
with(:body => {"bookmark_id"=>"1"}).
|
40
|
+
to_return(http_response('bookmarks_get_text_success'))
|
41
|
+
end
|
42
|
+
|
43
|
+
def stub_failed_bookmarks_get_text
|
44
|
+
stub_request(:post, "https://www.instapaper.com/api/1/bookmarks/get_text").
|
45
|
+
with(:body => {"bookmark_id"=>"2"}).
|
46
|
+
to_return(http_response('bookmarks_get_text_failure'))
|
47
|
+
end
|
48
|
+
|
49
|
+
def authenticated_client
|
50
|
+
InstapaperFull::API.new(:consumer_key => "key",
|
51
|
+
:consumer_secret => "secret",
|
52
|
+
:oauth_token => "token",
|
53
|
+
:oauth_token_secret => "tokensecret")
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_successful_authentication
|
57
|
+
stub_successful_authentication
|
58
|
+
stub_successful_verify_credentials
|
59
|
+
|
60
|
+
ip = InstapaperFull::API.new(:consumer_key => "test", :consumer_secret => "")
|
61
|
+
assert_equal true, ip.authenticate("tom@testing.com", "test")
|
62
|
+
assert_equal "thisisatoken", ip.options[:oauth_token]
|
63
|
+
assert_equal "thisisasecret", ip.options[:oauth_token_secret]
|
64
|
+
assert_equal 140230, ip.options[:user_id]
|
65
|
+
assert_equal "tom@tomtaylor.co.uk", ip.options[:username]
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_failed_authentication
|
69
|
+
stub_failed_authentication
|
70
|
+
|
71
|
+
ip = InstapaperFull::API.new(:consumer_key => "test", :consumer_secret => "")
|
72
|
+
assert_equal false, ip.authenticate("tom@testing.com", "test")
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_successful_bookmarks_list
|
76
|
+
stub_successful_bookmarks_list
|
77
|
+
list = authenticated_client.bookmarks_list
|
78
|
+
assert_equal 27, list.length # 25 + 1 user element + 1 meta element
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_failed_bookmarks_add
|
82
|
+
stub_failed_bookmarks_add
|
83
|
+
assert_raise(InstapaperFull::API::Error) { authenticated_client.bookmarks_add }
|
84
|
+
|
85
|
+
begin
|
86
|
+
authenticated_client.bookmarks_add
|
87
|
+
rescue InstapaperFull::API::Error => e
|
88
|
+
assert_equal 1240, e.code
|
89
|
+
assert_equal "Invalid URL specified", e.message
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_successful_bookmarks_get_text
|
94
|
+
stub_successful_bookmarks_get_text
|
95
|
+
|
96
|
+
html = authenticated_client.bookmarks_get_text(:bookmark_id => 1)
|
97
|
+
assert html.kind_of?(String)
|
98
|
+
assert_equal 22788, html.length
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_failed_bookmarks_get_text
|
102
|
+
stub_failed_bookmarks_get_text
|
103
|
+
|
104
|
+
assert_raise(InstapaperFull::API::Error) do
|
105
|
+
authenticated_client.bookmarks_get_text(:bookmark_id => 2)
|
106
|
+
end
|
107
|
+
|
108
|
+
begin
|
109
|
+
authenticated_client.bookmarks_get_text(:bookmark_id => 2)
|
110
|
+
rescue InstapaperFull::API::Error => e
|
111
|
+
assert_equal 1241, e.code
|
112
|
+
assert_equal "Invalid or missing bookmark_id", e.message
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
unless $LOAD_PATH.include? 'lib'
|
4
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
|
+
$LOAD_PATH.unshift(File.join($LOAD_PATH.first, '..', 'lib'))
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'instapaper_full'
|
9
|
+
require 'asset_helpers'
|
10
|
+
require 'webmock/test_unit'
|
11
|
+
|
12
|
+
WebMock.disable_net_connect!
|
metadata
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: instapaper_full
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Matt Biddulph
|
9
|
+
- Tom Taylor
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date: 2011-
|
13
|
+
date: 2011-12-02 00:00:00.000000000Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: faraday
|
16
|
-
requirement: &
|
17
|
+
requirement: &70362390471600 !ruby/object:Gem::Requirement
|
17
18
|
none: false
|
18
19
|
requirements:
|
19
20
|
- - ~>
|
@@ -21,10 +22,10 @@ dependencies:
|
|
21
22
|
version: 0.7.5
|
22
23
|
type: :runtime
|
23
24
|
prerelease: false
|
24
|
-
version_requirements: *
|
25
|
+
version_requirements: *70362390471600
|
25
26
|
- !ruby/object:Gem::Dependency
|
26
27
|
name: faraday_middleware
|
27
|
-
requirement: &
|
28
|
+
requirement: &70362390470240 !ruby/object:Gem::Requirement
|
28
29
|
none: false
|
29
30
|
requirements:
|
30
31
|
- - ~>
|
@@ -32,10 +33,10 @@ dependencies:
|
|
32
33
|
version: 0.7.0
|
33
34
|
type: :runtime
|
34
35
|
prerelease: false
|
35
|
-
version_requirements: *
|
36
|
+
version_requirements: *70362390470240
|
36
37
|
- !ruby/object:Gem::Dependency
|
37
38
|
name: simple_oauth
|
38
|
-
requirement: &
|
39
|
+
requirement: &70362390468680 !ruby/object:Gem::Requirement
|
39
40
|
none: false
|
40
41
|
requirements:
|
41
42
|
- - ~>
|
@@ -43,10 +44,10 @@ dependencies:
|
|
43
44
|
version: '0.1'
|
44
45
|
type: :runtime
|
45
46
|
prerelease: false
|
46
|
-
version_requirements: *
|
47
|
+
version_requirements: *70362390468680
|
47
48
|
- !ruby/object:Gem::Dependency
|
48
49
|
name: multi_json
|
49
|
-
requirement: &
|
50
|
+
requirement: &70362390468040 !ruby/object:Gem::Requirement
|
50
51
|
none: false
|
51
52
|
requirements:
|
52
53
|
- - ~>
|
@@ -54,10 +55,10 @@ dependencies:
|
|
54
55
|
version: 1.0.4
|
55
56
|
type: :runtime
|
56
57
|
prerelease: false
|
57
|
-
version_requirements: *
|
58
|
+
version_requirements: *70362390468040
|
58
59
|
- !ruby/object:Gem::Dependency
|
59
60
|
name: yajl-ruby
|
60
|
-
requirement: &
|
61
|
+
requirement: &70362390467080 !ruby/object:Gem::Requirement
|
61
62
|
none: false
|
62
63
|
requirements:
|
63
64
|
- - ~>
|
@@ -65,10 +66,10 @@ dependencies:
|
|
65
66
|
version: 1.1.0
|
66
67
|
type: :runtime
|
67
68
|
prerelease: false
|
68
|
-
version_requirements: *
|
69
|
+
version_requirements: *70362390467080
|
69
70
|
- !ruby/object:Gem::Dependency
|
70
71
|
name: rake
|
71
|
-
requirement: &
|
72
|
+
requirement: &70362390466520 !ruby/object:Gem::Requirement
|
72
73
|
none: false
|
73
74
|
requirements:
|
74
75
|
- - ! '>='
|
@@ -76,10 +77,33 @@ dependencies:
|
|
76
77
|
version: '0'
|
77
78
|
type: :development
|
78
79
|
prerelease: false
|
79
|
-
version_requirements: *
|
80
|
+
version_requirements: *70362390466520
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: test-unit
|
83
|
+
requirement: &70362390465540 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ~>
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 2.4.2
|
89
|
+
type: :development
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: *70362390465540
|
92
|
+
- !ruby/object:Gem::Dependency
|
93
|
+
name: webmock
|
94
|
+
requirement: &70362390463180 !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ~>
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 1.7.8
|
100
|
+
type: :development
|
101
|
+
prerelease: false
|
102
|
+
version_requirements: *70362390463180
|
80
103
|
description: See http://www.instapaper.com/api/full
|
81
104
|
email:
|
82
105
|
- mb@hackdiary.com
|
106
|
+
- tom@tomtaylor.co.uk
|
83
107
|
executables: []
|
84
108
|
extensions: []
|
85
109
|
extra_rdoc_files: []
|
@@ -90,8 +114,19 @@ files:
|
|
90
114
|
- README.md
|
91
115
|
- Rakefile
|
92
116
|
- instapaper_full.gemspec
|
117
|
+
- lib/errors.rb
|
93
118
|
- lib/instapaper_full.rb
|
94
119
|
- lib/instapaper_full/version.rb
|
120
|
+
- test/asset_helpers.rb
|
121
|
+
- test/http_responses/access_token_failure.txt
|
122
|
+
- test/http_responses/access_token_success.txt
|
123
|
+
- test/http_responses/bookmarks_add_failure.txt
|
124
|
+
- test/http_responses/bookmarks_get_text_failure.txt
|
125
|
+
- test/http_responses/bookmarks_get_text_success.txt
|
126
|
+
- test/http_responses/bookmarks_list_success.txt
|
127
|
+
- test/http_responses/verify_credentials_success.txt
|
128
|
+
- test/instapaper_api_test.rb
|
129
|
+
- test/test_helper.rb
|
95
130
|
homepage: https://github.com/mattb/instapaper_full
|
96
131
|
licenses: []
|
97
132
|
post_install_message:
|
@@ -104,17 +139,32 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
104
139
|
- - ! '>='
|
105
140
|
- !ruby/object:Gem::Version
|
106
141
|
version: '0'
|
142
|
+
segments:
|
143
|
+
- 0
|
144
|
+
hash: 3203290908794437357
|
107
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
146
|
none: false
|
109
147
|
requirements:
|
110
148
|
- - ! '>='
|
111
149
|
- !ruby/object:Gem::Version
|
112
150
|
version: '0'
|
151
|
+
segments:
|
152
|
+
- 0
|
153
|
+
hash: 3203290908794437357
|
113
154
|
requirements: []
|
114
155
|
rubyforge_project: instapaper_full
|
115
|
-
rubygems_version: 1.8.
|
156
|
+
rubygems_version: 1.8.10
|
116
157
|
signing_key:
|
117
158
|
specification_version: 3
|
118
159
|
summary: Wrapper for the Instapaper Full Developer API
|
119
|
-
test_files:
|
120
|
-
|
160
|
+
test_files:
|
161
|
+
- test/asset_helpers.rb
|
162
|
+
- test/http_responses/access_token_failure.txt
|
163
|
+
- test/http_responses/access_token_success.txt
|
164
|
+
- test/http_responses/bookmarks_add_failure.txt
|
165
|
+
- test/http_responses/bookmarks_get_text_failure.txt
|
166
|
+
- test/http_responses/bookmarks_get_text_success.txt
|
167
|
+
- test/http_responses/bookmarks_list_success.txt
|
168
|
+
- test/http_responses/verify_credentials_success.txt
|
169
|
+
- test/instapaper_api_test.rb
|
170
|
+
- test/test_helper.rb
|