readit 0.0.7 → 0.0.8
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/.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
|