instapaper_full 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|