readit 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +12 -0
- data/Gemfile +3 -1
- data/Readme.md +61 -5
- data/features/bookmarks.feature +9 -9
- data/features/readability.yml.sample +6 -0
- data/features/step_definitions/api_steps.rb +4 -4
- data/lib/readit/version.rb +1 -1
- data/lib/readit.rb +89 -11
- data/spec/cases/api_spec.rb +29 -6
- data/spec/cases/parser_spec.rb +19 -0
- data/spec/cases/tags_spec.rb +46 -0
- data/spec/cassettes/Readit_API/can_add_tags_to_one_bookmark.yml +699 -0
- data/spec/cassettes/Readit_API/can_fetch_all_tags_information_of_current_user.yml +45 -0
- data/spec/cassettes/Readit_API/can_fetch_tags_of_one_bookmark.yml +687 -0
- data/spec/cassettes/Readit_API/can_get_bookmark_location_when_bookmarked_a_url.yml +52 -0
- data/spec/cassettes/Readit_API/can_get_meta_infos_of_bookmarks.yml +646 -0
- data/spec/cassettes/Readit_API/can_remove_tag_info_of_one_bookmark_by_tag_id.yml +786 -0
- data/spec/cassettes/Readit_API/should_add_bookmark.yml +52 -0
- data/spec/cassettes/Readit_API/should_get_bookmarks_according_to_added_since.yml +86 -0
- data/spec/cassettes/Readit_API/should_get_the_article_content.yml +322 -0
- data/spec/cassettes/Readit_API/should_get_the_bookmark_info_by_bookmark_id.yml +713 -0
- data/spec/cassettes/Readit_API/should_get_user_infos.yml +51 -0
- data/spec/cassettes/Readit_API/should_get_user_s_bookmarks.yml +634 -0
- data/spec/cassettes/Readit_API/should_provide_the_bookmark_id_of_an_already_bookmarked_url.yml +683 -0
- data/spec/cassettes/Readit_API/should_update_bookmark_to_archive.yml +808 -0
- data/spec/cassettes/Readit_API/should_update_bookmark_to_favarite.yml +808 -0
- data/spec/cassettes/Readit_Parser/should_return_parsed_article_cotents.yml +638 -0
- data/spec/readability.yml.sample +7 -0
- data/spec/spec_helper.rb +28 -1
- metadata +65 -11
- data/readability.yml.sample +0 -3
@@ -0,0 +1,52 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://www.readability.com/api/rest/v1/bookmarks
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: url=http%3A%2F%2Fwww.tripadvisor.com%2FRestaurant_Review-g297701-d1182615-Reviews-Cafe_Lotus-Ubud_Bali.html
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- ! '*/*'
|
12
|
+
User-Agent:
|
13
|
+
- OAuth gem v0.4.7
|
14
|
+
Content-Length:
|
15
|
+
- '0'
|
16
|
+
Content-Type:
|
17
|
+
- application/x-www-form-urlencoded
|
18
|
+
Authorization:
|
19
|
+
- OAuth oauth_consumer_key="<TOKENS>", oauth_nonce="LxDHPjGRmZ3krV9MEDEUhlD9RzfDb6WL6vdL5VwF3Es",
|
20
|
+
oauth_signature="yDdXZC4itrqQHzLT8YTStpA%2FNvs%3D", oauth_signature_method="HMAC-SHA1",
|
21
|
+
oauth_timestamp="1361335756", oauth_token="<TOKENS>", oauth_version="1.0"
|
22
|
+
response:
|
23
|
+
status:
|
24
|
+
code: 409
|
25
|
+
message: CONFLICT
|
26
|
+
headers:
|
27
|
+
Content-Type:
|
28
|
+
- application/json
|
29
|
+
Date:
|
30
|
+
- Wed, 20 Feb 2013 04:49:13 GMT
|
31
|
+
Location:
|
32
|
+
- https://www.readability.com/api/rest/v1/bookmarks/2420783
|
33
|
+
P3p:
|
34
|
+
- CP='Legacy Only. Go to https://readability.com/about/terms/ for full terms.'
|
35
|
+
Server:
|
36
|
+
- nginx/1.2.1
|
37
|
+
Set-Cookie:
|
38
|
+
- readabilityToken=4FCRyvwJt8enJ7LvesTWKphGwNRyT5h9B3t5KWfP; expires=Wed, 20-Mar-2013
|
39
|
+
04:49:13 GMT; Max-Age=2419200; Path=/
|
40
|
+
Vary:
|
41
|
+
- Authorization, Cookie
|
42
|
+
Content-Length:
|
43
|
+
- '117'
|
44
|
+
Connection:
|
45
|
+
- keep-alive
|
46
|
+
body:
|
47
|
+
encoding: US-ASCII
|
48
|
+
string: ! '{"meta": {"redirect": true, "existing_bookmark": 2420783}, "messages":
|
49
|
+
["Bookmark already exists."], "success": true}'
|
50
|
+
http_version:
|
51
|
+
recorded_at: Wed, 20 Feb 2013 04:49:16 GMT
|
52
|
+
recorded_with: VCR 2.0.1
|
@@ -0,0 +1,86 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://www.readability.com/api/rest/v1/bookmarks?added_until=2012-1-1&per_page=2
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- ! '*/*'
|
12
|
+
User-Agent:
|
13
|
+
- OAuth gem v0.4.7
|
14
|
+
Authorization:
|
15
|
+
- OAuth oauth_consumer_key="<TOKENS>", oauth_nonce="Xc8HCVOzxhpz8sgPCUVDer3spA2TLJy4FMBQcDIcolI",
|
16
|
+
oauth_signature="cX%2FCeK0pYubEOv07oH0333F7%2BKM%3D", oauth_signature_method="HMAC-SHA1",
|
17
|
+
oauth_timestamp="1361335761", oauth_token="<TOKENS>", oauth_version="1.0"
|
18
|
+
response:
|
19
|
+
status:
|
20
|
+
code: 200
|
21
|
+
message: OK
|
22
|
+
headers:
|
23
|
+
Content-Type:
|
24
|
+
- application/json; charset=utf-8
|
25
|
+
Date:
|
26
|
+
- Wed, 20 Feb 2013 04:49:17 GMT
|
27
|
+
P3p:
|
28
|
+
- CP='Legacy Only. Go to https://readability.com/about/terms/ for full terms.'
|
29
|
+
Server:
|
30
|
+
- nginx/1.2.1
|
31
|
+
Set-Cookie:
|
32
|
+
- readabilityToken=4FCRyvwJt8enJ7LvesTWKphGwNRyT5h9B3t5KWfP; expires=Wed, 20-Mar-2013
|
33
|
+
04:49:17 GMT; Max-Age=2419200; Path=/
|
34
|
+
Vary:
|
35
|
+
- Accept-Encoding
|
36
|
+
- Authorization, Cookie
|
37
|
+
Content-Length:
|
38
|
+
- '3068'
|
39
|
+
Connection:
|
40
|
+
- keep-alive
|
41
|
+
body:
|
42
|
+
encoding: US-ASCII
|
43
|
+
string: ! "{\n \"bookmarks\": [\n {\n \"user_id\": 24591,\n
|
44
|
+
\ \"read_percent\": \"0.00\",\n \"tags\": [],\n \"date_updated\":
|
45
|
+
\"2012-01-16 21:48:53\",\n \"favorite\": false,\n \"id\":
|
46
|
+
1836432,\n \"date_archived\": \"2012-01-16 21:48:53\",\n \"date_opened\":
|
47
|
+
null,\n \"article\": {\n \"domain\": \"www.everpix.com\",\n
|
48
|
+
\ \"title\": \"Everpix\",\n \"url\": \"https://www.everpix.com/#year=2010\",\n
|
49
|
+
\ \"lead_image_url\": null,\n \"author\": null,\n
|
50
|
+
\ \"excerpt\": \"From Aug 22, 4:38 PM to Jun 10, 8:05 PM\",\n
|
51
|
+
\ \"direction\": \"ltr\",\n \"word_count\": 506,\n
|
52
|
+
\ \"date_published\": null,\n \"dek\": null,\n
|
53
|
+
\ \"processed\": true,\n \"id\": \"uunhk2gr\"\n
|
54
|
+
\ },\n \"article_href\": \"/api/rest/v1/articles/uunhk2gr\",\n
|
55
|
+
\ \"date_favorited\": null,\n \"date_added\": \"2011-12-30
|
56
|
+
21:43:48\",\n \"archive\": true\n },\n {\n \"user_id\":
|
57
|
+
24591,\n \"read_percent\": \"0.00\",\n \"tags\": [],\n
|
58
|
+
\ \"date_updated\": \"2012-01-16 21:48:58\",\n \"favorite\":
|
59
|
+
false,\n \"id\": 1834877,\n \"date_archived\": \"2012-01-16
|
60
|
+
21:48:58\",\n \"date_opened\": null,\n \"article\":
|
61
|
+
{\n \"domain\": \"hangar.runway7.net\",\n \"title\":
|
62
|
+
\"The Javascript Guide to Objects, Functions, Closures and Scope\",\n \"url\":
|
63
|
+
\"http://hangar.runway7.net/javascript-guide-to-objects-functions-scope-prototpyes-closures\",\n
|
64
|
+
\ \"lead_image_url\": null,\n \"author\": null,\n
|
65
|
+
\ \"excerpt\": \"Dec 26, 2011 Throughout my time writing Javascript
|
66
|
+
code, I've come to realize that while I love the language to bits, it is a
|
67
|
+
little difficult to understand. A lot of people have attributed this to…\",\n
|
68
|
+
\ \"direction\": \"ltr\",\n \"word_count\": 1941,\n
|
69
|
+
\ \"date_published\": null,\n \"dek\": null,\n
|
70
|
+
\ \"processed\": true,\n \"id\": \"obhnzmjt\"\n
|
71
|
+
\ },\n \"article_href\": \"/api/rest/v1/articles/obhnzmjt\",\n
|
72
|
+
\ \"date_favorited\": null,\n \"date_added\": \"2011-12-30
|
73
|
+
19:24:44\",\n \"archive\": true\n }\n ],\n \"meta\":
|
74
|
+
{\n \"num_pages\": 28,\n \"page\": 1,\n \"item_count_total\":
|
75
|
+
55,\n \"item_count\": 2\n },\n \"conditions\": {\n \"opened_since\":
|
76
|
+
null,\n \"added_until\": \"2012-01-01 00:00:00\",\n \"domain\":
|
77
|
+
\"\",\n \"updated_until\": null,\n \"tags\": [],\n \"archive\":
|
78
|
+
null,\n \"archived_until\": null,\n \"favorite\": null,\n \"opened_until\":
|
79
|
+
null,\n \"archived_since\": null,\n \"favorited_since\": null,\n
|
80
|
+
\ \"updated_since\": null,\n \"exclude_accessibility\": \"\",\n
|
81
|
+
\ \"per_page\": 2,\n \"favorited_until\": null,\n \"order\":
|
82
|
+
\"-date_added\",\n \"only_deleted\": null,\n \"page\": 1,\n
|
83
|
+
\ \"added_since\": null,\n \"user\": \"<TOKENS>\"\n }\n}"
|
84
|
+
http_version:
|
85
|
+
recorded_at: Wed, 20 Feb 2013 04:49:21 GMT
|
86
|
+
recorded_with: VCR 2.0.1
|
@@ -0,0 +1,322 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://www.readability.com/api/rest/v1/articles/eg60dxbv
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- ! '*/*'
|
12
|
+
User-Agent:
|
13
|
+
- OAuth gem v0.4.7
|
14
|
+
Authorization:
|
15
|
+
- OAuth oauth_consumer_key="<TOKENS>", oauth_nonce="Tqe0Nusx85HijyKr71dEJFRitn0d9Cn3O4DDGKNjFj8",
|
16
|
+
oauth_signature="LmJ8MmzMdlFqyyPDUi0C%2FsbMnKQ%3D", oauth_signature_method="HMAC-SHA1",
|
17
|
+
oauth_timestamp="1361335758", oauth_token="<TOKENS>", oauth_version="1.0"
|
18
|
+
response:
|
19
|
+
status:
|
20
|
+
code: 200
|
21
|
+
message: OK
|
22
|
+
headers:
|
23
|
+
Content-Type:
|
24
|
+
- application/json; charset=utf-8
|
25
|
+
Date:
|
26
|
+
- Wed, 20 Feb 2013 04:49:15 GMT
|
27
|
+
P3p:
|
28
|
+
- CP='Legacy Only. Go to https://readability.com/about/terms/ for full terms.'
|
29
|
+
Server:
|
30
|
+
- nginx/1.2.1
|
31
|
+
Set-Cookie:
|
32
|
+
- readabilityToken=4FCRyvwJt8enJ7LvesTWKphGwNRyT5h9B3t5KWfP; expires=Wed, 20-Mar-2013
|
33
|
+
04:49:15 GMT; Max-Age=2419200; Path=/
|
34
|
+
Vary:
|
35
|
+
- Accept-Encoding
|
36
|
+
- Authorization, Cookie
|
37
|
+
Content-Length:
|
38
|
+
- '22030'
|
39
|
+
Connection:
|
40
|
+
- keep-alive
|
41
|
+
body:
|
42
|
+
encoding: US-ASCII
|
43
|
+
string: ! "{\n \"direction\": \"ltr\",\n \"next_page_href\": null,\n \"author\":
|
44
|
+
null,\n \"url\": \"http://www.joezimjs.com/javascript/javascript-design-patterns-decorator/?utm_source=javascriptweekly&utm_medium=email\",\n
|
45
|
+
\ \"lead_image_url\": \"http://www.joezimjs.com/wp-content/uploads/decorator_structure.png\",\n
|
46
|
+
\ \"title\": \"JavaScript Design Patterns: Decorator\",\n \"excerpt\":
|
47
|
+
\"Today I’d like to show another JavaScript Design Pattern: the Decorator,
|
48
|
+
which is a way to add features to objects without subclassing or adding extra
|
49
|
+
attributes. This post continues the…\",\n \"domain\": \"www.joezimjs.com\",\n
|
50
|
+
\ \"word_count\": 1351,\n \"content\": \"<div><div class=\\\"entry-content\\\">\\n\\n\\t\\t<p>Today
|
51
|
+
I’d like to show another JavaScript Design Pattern: the Decorator,
|
52
|
+
which is a way to add features to objects without subclassing or adding extra
|
53
|
+
attributes. This post continues the JavaScript Design Patterns series that
|
54
|
+
I started several months ago. If you’re new to the JavaScript Design
|
55
|
+
Patterns series that I’m running here, you can find a list of the previous
|
56
|
+
and upcoming posts in the series at the <a href=\\\"http://www.joezimjs.com/javascript/javascript-design-patterns-decorator/#series\\\">bottom
|
57
|
+
of the post</a>.</p>\\n<h2>Back on Course with Tutorial Posts</h2>\\n<p>After
|
58
|
+
the exciting launch of my new <a href=\\\"http://www.joezimjs.com/projects/publish-subscribe-jquery-plugin/\\\"
|
59
|
+
title=\\\"JZ Publish/Subscribe Project Page\\\">jQuery plugin</a> it’s
|
60
|
+
been difficult to bring myself back to normal blogging and back to this series.
|
61
|
+
If you don’t know what I’m talking about, then you should hop
|
62
|
+
on over to the <a href=\\\"http://www.joezimjs.com/javascript/new-jquery-plugin-publish-subscribe/\\\"
|
63
|
+
title=\\\"New jQuery Plugin: Publish/Subscribe\\\">plugin’s announcement
|
64
|
+
post</a> (when you’re done reading this, of course). However, regardless
|
65
|
+
of how this month started out, I’ve decided to make a commitment to
|
66
|
+
at least 2 “tutorial” posts per month. I put the word “tutorial”
|
67
|
+
in quotes because I’m not sure they can all be generally considered
|
68
|
+
tutorials, but I’m using the word to mean any post whose purpose is
|
69
|
+
to teach, as opposed to announcements or news and the like.</p>\\n<h2>On with
|
70
|
+
the Decorator Pattern</h2>\\n<p>Let’s return to purpose of this post:
|
71
|
+
learning about the decorator pattern. Like I said, this pattern permits us
|
72
|
+
to add features to an object without needing to subclass it. Instead we “decorate”
|
73
|
+
(wrap) it with another object with the same interface that has the one feature
|
74
|
+
we’re adding. To get a better idea of what I’m talking about,
|
75
|
+
let’s first demonstrate how someone lacking knowledge of the decorator
|
76
|
+
pattern would attempt this, especially if they’re coming from a background
|
77
|
+
of classical inheritance.</p>\\n<div class=\\\"geshi javascript\\\">\\n<ol><li
|
78
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span class=\\\"co1\\\">// Superclass</span></p>\\n</li>\\n<li
|
79
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span class=\\\"kw2\\\">var</span>
|
80
|
+
Car = <span class=\\\"kw2\\\">function</span><span class=\\\"br0\\\">(</span><span
|
81
|
+
class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span>…<span class=\\\"br0\\\">}</span>;</p>\\n</li>\\n\\n<li
|
82
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span class=\\\"co1\\\">// Subclasses
|
83
|
+
with different features</span></p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span
|
84
|
+
class=\\\"kw2\\\">var</span> CarWithPowerLocks = <span class=\\\"kw2\\\">function</span><span
|
85
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span>…<span
|
86
|
+
class=\\\"br0\\\">}</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span
|
87
|
+
class=\\\"kw2\\\">var</span> CarWithPowerWindows = <span class=\\\"kw2\\\">function</span><span
|
88
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span>…<span
|
89
|
+
class=\\\"br0\\\">}</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span
|
90
|
+
class=\\\"kw2\\\">var</span> CarWithPowerLocksAndPowerWindows = <span class=\\\"kw2\\\">function</span><span
|
91
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span>…<span
|
92
|
+
class=\\\"br0\\\">}</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span
|
93
|
+
class=\\\"kw2\\\">var</span> CarWithAC = <span class=\\\"kw2\\\">function</span><span
|
94
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span>…<span
|
95
|
+
class=\\\"br0\\\">}</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span
|
96
|
+
class=\\\"kw2\\\">var</span> CarWithACAndPowerLocks = <span class=\\\"kw2\\\">function</span><span
|
97
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span>…<span
|
98
|
+
class=\\\"br0\\\">}</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span
|
99
|
+
class=\\\"kw2\\\">var</span> CarWithACAndPowerWindows = <span class=\\\"kw2\\\">function</span><span
|
100
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span>…<span
|
101
|
+
class=\\\"br0\\\">}</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span
|
102
|
+
class=\\\"kw2\\\">var</span> CarWithACAndPowerLocksAndPowerWindows = <span
|
103
|
+
class=\\\"kw2\\\">function</span><span class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span>
|
104
|
+
<span class=\\\"br0\\\">{</span>…<span class=\\\"br0\\\">}</span>;</p>\\n</li>\\n<li
|
105
|
+
class=\\\"li1\\\">\\n\\n</li>\\n</ol></div>\\n<p>As you can see, every combination
|
106
|
+
of features needs to be represented by a new “class”. This might
|
107
|
+
be okay if you have only a couple features, but once you start growing the
|
108
|
+
number of features, this becomes more and more of a nightmare. Of course,
|
109
|
+
if you want to be a jerk, you can do this in an app and leave it for someone
|
110
|
+
else to maintain, but I don’t know how long you’d go before
|
111
|
+
being punched in the face if that programmer needs to add another feature
|
112
|
+
(or 5 more!).</p>\\n<h2>How the Decorator Pattern can Help</h2>\\n<p>Thankfully
|
113
|
+
the Decorator Pattern can make things considerably simpler for us and future
|
114
|
+
maintainers of our code. First we’ll create the base object that will
|
115
|
+
be a <code>Car</code> with no cool features. This also sets up the interface
|
116
|
+
that the decorators will use.</p>\\n<div class=\\\"geshi javascript\\\">\\n<ol><li
|
117
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span class=\\\"kw2\\\">var</span>
|
118
|
+
Car = <span class=\\\"kw2\\\">function</span><span class=\\\"br0\\\">(</span><span
|
119
|
+
class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
120
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">    console.<span class=\\\"me1\\\">log</span><span
|
121
|
+
class=\\\"br0\\\">(</span><span class=\\\"st0\\\">'Assemble: build frame,
|
122
|
+
add core parts'</span><span class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li
|
123
|
+
class=\\\"li1\\\">\\n\\n</li>\\n\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span
|
124
|
+
class=\\\"co1\\\">// The decorators will also need to implement these functions</span></p>\\n</li>\\n<li
|
125
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span class=\\\"co1\\\">// to comply
|
126
|
+
with Car's interface.</span></p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\">Car.<span
|
127
|
+
class=\\\"me1\\\">prototype</span> = <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
128
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">    start: <span class=\\\"kw2\\\">function</span><span
|
129
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
130
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">        console.<span
|
131
|
+
class=\\\"me1\\\">log</span><span class=\\\"br0\\\">(</span><span class=\\\"st0\\\">'The
|
132
|
+
engine starts with roar!'</span><span class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li
|
133
|
+
class=\\\"li1\\\">\\n\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"> 
|
134
|
+
  drive: <span class=\\\"kw2\\\">function</span><span class=\\\"br0\\\">(</span><span
|
135
|
+
class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
136
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">        console.<span
|
137
|
+
class=\\\"me1\\\">log</span><span class=\\\"br0\\\">(</span><span class=\\\"st0\\\">'Away
|
138
|
+
we go!'</span><span class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n\\n</li>\\n<li
|
139
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">    getPrice: <span class=\\\"kw2\\\">function</span><span
|
140
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
141
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">        <span
|
142
|
+
class=\\\"kw1\\\">return</span> <span class=\\\"nu0\\\">11000.00</span>;</p>\\n</li>\\n<li
|
143
|
+
class=\\\"li1\\\">\\n\\n</li>\\n<li class=\\\"li1\\\">\\n\\n</li>\\n</ol></div>\\n<p>Now
|
144
|
+
we’ll create the decorator “class” that each of the decorator
|
145
|
+
will inherit from. You’ll notice that each of the functions simply
|
146
|
+
pass the call on to the <code>Car</code> that they’re wrapping. In
|
147
|
+
this case the only functions that will be overridden are <code>assemble</code>
|
148
|
+
and <code>getPrice</code>.</p>\\n<div class=\\\"geshi javascript\\\">\\n<ol><li
|
149
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span class=\\\"co1\\\">// You need
|
150
|
+
to pass in the Car (or CarDecorator) in order to</span></p>\\n</li>\\n<li
|
151
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span class=\\\"co1\\\">// be able
|
152
|
+
to add features to it.</span></p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span
|
153
|
+
class=\\\"kw2\\\">var</span> CarDecorator = <span class=\\\"kw2\\\">function</span><span
|
154
|
+
class=\\\"br0\\\">(</span>car<span class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
155
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">    <span class=\\\"kw1\\\">this</span>.<span
|
156
|
+
class=\\\"me1\\\">car</span> = car;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n\\n</li>\\n\\n<li
|
157
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span class=\\\"co1\\\">// CarDecorator
|
158
|
+
is implementing the same interface</span></p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p
|
159
|
+
class=\\\"de1\\\">CarDecorator.<span class=\\\"me1\\\">prototype</span> =
|
160
|
+
<span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p
|
161
|
+
class=\\\"de1\\\">    start: <span class=\\\"kw2\\\">function</span><span
|
162
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
163
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">        <span
|
164
|
+
class=\\\"kw1\\\">this</span>.<span class=\\\"me1\\\">car</span>.<span class=\\\"me1\\\">start</span><span
|
165
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li
|
166
|
+
class=\\\"li1\\\">\\n\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"> 
|
167
|
+
  drive: <span class=\\\"kw2\\\">function</span><span class=\\\"br0\\\">(</span><span
|
168
|
+
class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
169
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">        <span
|
170
|
+
class=\\\"kw1\\\">this</span>.<span class=\\\"me1\\\">car</span>.<span class=\\\"me1\\\">drive</span><span
|
171
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li
|
172
|
+
class=\\\"li1\\\">\\n\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"> 
|
173
|
+
  getPrice: <span class=\\\"kw2\\\">function</span><span class=\\\"br0\\\">(</span><span
|
174
|
+
class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
175
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">        <span
|
176
|
+
class=\\\"kw1\\\">return</span> <span class=\\\"kw1\\\">this</span>.<span
|
177
|
+
class=\\\"me1\\\">car</span>.<span class=\\\"me1\\\">getPrice</span><span
|
178
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li
|
179
|
+
class=\\\"li1\\\">\\n\\n</li>\\n<li class=\\\"li1\\\">\\n\\n</li>\\n</ol></div>\\n<p>Next
|
180
|
+
we create a decorator object for each feature and override the parent’s
|
181
|
+
functions whenever we want to add more or different functionality there.</p>\\n<div
|
182
|
+
class=\\\"geshi javascript\\\">\\n<ol><li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span
|
183
|
+
class=\\\"kw2\\\">var</span> PowerLocksDecorator = <span class=\\\"kw2\\\">function</span><span
|
184
|
+
class=\\\"br0\\\">(</span>car<span class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
185
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">    <span class=\\\"co1\\\">//
|
186
|
+
JavaScript's way of calling a parent class' constructor</span></p>\\n</li>\\n<li
|
187
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">    CarDecorator.<span
|
188
|
+
class=\\\"me1\\\">call</span><span class=\\\"br0\\\">(</span><span class=\\\"kw1\\\">this</span>,
|
189
|
+
car<span class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p
|
190
|
+
class=\\\"de1\\\">    console.<span class=\\\"me1\\\">log</span><span
|
191
|
+
class=\\\"br0\\\">(</span><span class=\\\"st0\\\">'Assemble: add power locks'</span><span
|
192
|
+
class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n\\n</li>\\n<li
|
193
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">PowerLocksDecorator.<span class=\\\"me1\\\">prototype</span>
|
194
|
+
= <span class=\\\"kw2\\\">new</span> CarDecorator<span class=\\\"br0\\\">(</span><span
|
195
|
+
class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\">PowerLocksDecorator.<span
|
196
|
+
class=\\\"me1\\\">prototype</span>.<span class=\\\"me1\\\">drive</span> =
|
197
|
+
<span class=\\\"kw2\\\">function</span><span class=\\\"br0\\\">(</span><span
|
198
|
+
class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
199
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">    <span class=\\\"co1\\\">//
|
200
|
+
You can either do this</span></p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"> 
|
201
|
+
  <span class=\\\"kw1\\\">this</span>.<span class=\\\"me1\\\">car</span>.<span
|
202
|
+
class=\\\"me1\\\">drive</span><span class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li
|
203
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">    <span class=\\\"co1\\\">//
|
204
|
+
or you can call the parent's drive function:</span></p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p
|
205
|
+
class=\\\"de1\\\">    <span class=\\\"co1\\\">// CarDecorator.prototype.drive.call(this);</span></p>\\n</li>\\n<li
|
206
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">    console.<span class=\\\"me1\\\">log</span><span
|
207
|
+
class=\\\"br0\\\">(</span><span class=\\\"st0\\\">'The doors automatically
|
208
|
+
lock'</span><span class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n\\n</li>\\n\\n<li
|
209
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span class=\\\"kw2\\\">var</span>
|
210
|
+
PowerWindowsDecorator = <span class=\\\"kw2\\\">function</span><span class=\\\"br0\\\">(</span>car<span
|
211
|
+
class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
212
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">    CarDecorator.<span
|
213
|
+
class=\\\"me1\\\">call</span><span class=\\\"br0\\\">(</span><span class=\\\"kw1\\\">this</span>,
|
214
|
+
car<span class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p
|
215
|
+
class=\\\"de1\\\">    console.<span class=\\\"me1\\\">log</span><span
|
216
|
+
class=\\\"br0\\\">(</span><span class=\\\"st0\\\">'Assemble: add power windows'</span><span
|
217
|
+
class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n\\n</li>\\n<li
|
218
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">PowerWindowsDecorator.<span class=\\\"me1\\\">prototype</span>
|
219
|
+
= <span class=\\\"kw2\\\">new</span> CarDecorator<span class=\\\"br0\\\">(</span><span
|
220
|
+
class=\\\"br0\\\">)</span>;</p>\\n</li>\\n\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span
|
221
|
+
class=\\\"kw2\\\">var</span> ACDecorator = <span class=\\\"kw2\\\">function</span><span
|
222
|
+
class=\\\"br0\\\">(</span>car<span class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
223
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">    CarDecorator.<span
|
224
|
+
class=\\\"me1\\\">call</span><span class=\\\"br0\\\">(</span><span class=\\\"kw1\\\">this</span>,
|
225
|
+
car<span class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p
|
226
|
+
class=\\\"de1\\\">    console.<span class=\\\"me1\\\">log</span><span
|
227
|
+
class=\\\"br0\\\">(</span><span class=\\\"st0\\\">'Assemble: add A/C unit'</span><span
|
228
|
+
class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n\\n</li>\\n<li
|
229
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">ACDecorator.<span class=\\\"me1\\\">prototype</span>
|
230
|
+
= <span class=\\\"kw2\\\">new</span> CarDecorator<span class=\\\"br0\\\">(</span><span
|
231
|
+
class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\">ACDecorator.<span
|
232
|
+
class=\\\"me1\\\">prototype</span>.<span class=\\\"me1\\\">start</span> =
|
233
|
+
<span class=\\\"kw2\\\">function</span><span class=\\\"br0\\\">(</span><span
|
234
|
+
class=\\\"br0\\\">)</span> <span class=\\\"br0\\\">{</span></p>\\n</li>\\n<li
|
235
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\">    <span class=\\\"kw1\\\">this</span>.<span
|
236
|
+
class=\\\"me1\\\">car</span>.<span class=\\\"me1\\\">start</span><span class=\\\"br0\\\">(</span><span
|
237
|
+
class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"> 
|
238
|
+
  console.<span class=\\\"me1\\\">log</span><span class=\\\"br0\\\">(</span><span
|
239
|
+
class=\\\"st0\\\">'The cool air starts blowing.'</span><span class=\\\"br0\\\">)</span>;</p>\\n</li>\\n<li
|
240
|
+
class=\\\"li1\\\">\\n\\n</li>\\n</ol></div>\\n<p>Notice that we always call
|
241
|
+
the same function on the wrapped object as well. This is somewhat similar
|
242
|
+
to the way a <a href=\\\"http://www.joezimjs.com/javascript/javascript-design-patterns-composite/\\\"
|
243
|
+
title=\\\"JavaScript Design Patterns: Composite\\\">composite</a> works, though
|
244
|
+
the similarities between the two patterns pretty much end there. In this example,
|
245
|
+
we always call the wrapped object’s function first before adding in
|
246
|
+
the new information from the decorator (if any exists for that function).
|
247
|
+
This creates the desired effect of having the core functions executing first,
|
248
|
+
\ but other applications might require different order, or possibly might
|
249
|
+
not even call the wrapped object’s function if the intention is to
|
250
|
+
completely change the functionality rather than adding on to it.</p>\\n<p><img
|
251
|
+
src=\\\"http://www.joezimjs.com/wp-content/uploads/decorator_structure.png\\\"
|
252
|
+
alt=\\\"Structure of the Decorator Pattern\\\" title=\\\"Structure of the
|
253
|
+
Decorator Pattern\\\" width=\\\"570\\\" class=\\\"alignnone size-full wp-image-351\\\"></p>\\n<h2>Seeing
|
254
|
+
our JavaScript in Action</h2>\\n<p>So how do we use the code that we just
|
255
|
+
spent this entire time making? Well the actual code is below, but maybe I
|
256
|
+
should do a little explaining first. Of course, you’re free to skip
|
257
|
+
this and jump straight to the code if you think you’ve got it down.</p>\\n<p>First
|
258
|
+
we create a <code>Car</code> object. Then, we create the decorator for the
|
259
|
+
feature we want to add onto it and pass the <code>Car</code> into its constructor.
|
260
|
+
The object returned from the decorator’s constructor is assigned back
|
261
|
+
to the variable that previously held the <code>Car</code> object because since
|
262
|
+
the decorators use the same interface, they too can be considered <code>Car</code>s.
|
263
|
+
We keep adding more features until we’re satisfied and then we have
|
264
|
+
our desired car that we can do whatever we want with.</p>\\n<div class=\\\"geshi
|
265
|
+
javascript\\\">\\n<ol><li class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span
|
266
|
+
class=\\\"kw2\\\">var</span> car = <span class=\\\"kw2\\\">new</span> Car<span
|
267
|
+
class=\\\"br0\\\">(</span><span class=\\\"br0\\\">)</span>;    
|
268
|
+
               <span class=\\\"co1\\\">//
|
269
|
+
log \\\"Assemble: build frame, add core parts\\\"</span></p>\\n</li>\\n\\n<li
|
270
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span class=\\\"co1\\\">// give
|
271
|
+
the car some power windows</span></p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p
|
272
|
+
class=\\\"de1\\\">car = <span class=\\\"kw2\\\">new</span> PowerWindowDecorator<span
|
273
|
+
class=\\\"br0\\\">(</span>car<span class=\\\"br0\\\">)</span>;    <span
|
274
|
+
class=\\\"co1\\\">// log \\\"Assemble: add power windows\\\"</span></p>\\n</li>\\n\\n<li
|
275
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span class=\\\"co1\\\">// now some
|
276
|
+
power locks and A/C</span></p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\">car
|
277
|
+
= <span class=\\\"kw2\\\">new</span> PowerLocksDecorator<span class=\\\"br0\\\">(</span>car<span
|
278
|
+
class=\\\"br0\\\">)</span>;     <span class=\\\"co1\\\">// log \\\"Assemble:
|
279
|
+
add power locks\\\"</span></p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p class=\\\"de1\\\">car
|
280
|
+
= <span class=\\\"kw2\\\">new</span> ACDecorator<span class=\\\"br0\\\">(</span>car<span
|
281
|
+
class=\\\"br0\\\">)</span>;             <span
|
282
|
+
class=\\\"co1\\\">// log \\\"Assemble: add A/C unit\\\"</span></p>\\n</li>\\n\\n<li
|
283
|
+
class=\\\"li1\\\">\\n<p class=\\\"de1\\\"><span class=\\\"co1\\\">// let's
|
284
|
+
start this bad boy up and take a drive!</span></p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p
|
285
|
+
class=\\\"de1\\\">car.<span class=\\\"me1\\\">start</span><span class=\\\"br0\\\">(</span><span
|
286
|
+
class=\\\"br0\\\">)</span>; <span class=\\\"co1\\\">// log 'The engine starts
|
287
|
+
with roar!' and 'The cool air starts blowing.'</span></p>\\n</li>\\n<li class=\\\"li1\\\">\\n<p
|
288
|
+
class=\\\"de1\\\">car.<span class=\\\"me1\\\">drive</span><span class=\\\"br0\\\">(</span><span
|
289
|
+
class=\\\"br0\\\">)</span>; <span class=\\\"co1\\\">// log 'Away we go!' and
|
290
|
+
'The doors automatically lock'</span></p>\\n</li>\\n</ol></div>\\n<h2>Concluding
|
291
|
+
this Fiasco</h2>\\n<p>The Decorator proves to be a nice way of maintaining
|
292
|
+
differentiating features for an object and definitely helps improve maintainability
|
293
|
+
over the long haul. You may have noticed, though, that I didn’t include
|
294
|
+
any code to make sure that we didn’t accidentally add the same feature
|
295
|
+
more than once. Don’t worry, the next post will give us a clean answer
|
296
|
+
without having to change any of the code we’ve already written. Adding
|
297
|
+
checks into the decorators to accomplish would prove to be annoying.</p>\\n<p>If
|
298
|
+
you’ve got something to say about the Decorator Pattern, this post,
|
299
|
+
or even just JavaScript in general, make your voice heard in the comments
|
300
|
+
section below. I’d love to hear it, even if you’re just letting
|
301
|
+
me know I’m an idiot (just try to make it more constructive than “you’re
|
302
|
+
an idiot”). We all have to grow somehow. Also, I’d greatly appreciate
|
303
|
+
if you’d use the social sharing buttons below to spread the word about
|
304
|
+
this post. Little guys like me don’t get big without some help. Happy
|
305
|
+
Coding!</p>\\n<p id=\\\"series\\\">JavaScript Design Patterns series:</p>\\n<ol
|
306
|
+
class=\\\"yarpp-posts\\\"><li><a href=\\\"http://www.joezimjs.com/javascript/javascript-design-patterns-adapter/\\\"
|
307
|
+
rel=\\\"bookmark\\\" title=\\\"JavaScript Design Patterns: Adapter\\\">JavaScript
|
308
|
+
Design Patterns: Adapter</a></li>\\n<li><a href=\\\"http://www.joezimjs.com/javascript/javascript-design-patterns-singleton/\\\"
|
309
|
+
rel=\\\"bookmark\\\" title=\\\"JavaScript Design Patterns: Singleton\\\">JavaScript
|
310
|
+
Design Patterns: Singleton</a></li>\\n<li><a href=\\\"http://www.joezimjs.com/javascript/javascript-design-patterns-composite/\\\"
|
311
|
+
rel=\\\"bookmark\\\" title=\\\"JavaScript Design Patterns: Composite\\\">JavaScript
|
312
|
+
Design Patterns: Composite</a></li>\\n<li><a href=\\\"http://www.joezimjs.com/javascript/javascript-design-patterns-bridge/\\\"
|
313
|
+
rel=\\\"bookmark\\\" title=\\\"JavaScript Design Patterns: Bridge\\\">JavaScript
|
314
|
+
Design Patterns: Bridge</a></li>\\n<li><a href=\\\"http://www.joezimjs.com/javascript/javascript-design-patterns-facade/\\\"
|
315
|
+
rel=\\\"bookmark\\\" title=\\\"JavaScript Design Patterns: Facade\\\">JavaScript
|
316
|
+
Design Patterns: Facade</a></li>\\n</ol><br class=\\\"clear\\\"></div>\\n\\n\\t</div>\",\n
|
317
|
+
\ \"date_published\": null,\n \"dek\": null,\n \"processed\": true,\n
|
318
|
+
\ \"content_size\": 20088,\n \"short_url\": \"http://rdd.me/eg60dxbv\",\n
|
319
|
+
\ \"id\": \"eg60dxbv\"\n}"
|
320
|
+
http_version:
|
321
|
+
recorded_at: Wed, 20 Feb 2013 04:49:19 GMT
|
322
|
+
recorded_with: VCR 2.0.1
|