html2markdown 0.0.2 → 0.0.3
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/Gemfile +2 -0
- data/Readme.md +22 -3
- data/fixtures/vcr_cassettes/html_page.yml +545 -0
- data/html2markdown.gemspec +1 -1
- data/lib/html2markdown/converter.rb +2 -0
- data/lib/html2markdown/html_page.rb +1 -1
- data/lib/html2markdown/version.rb +1 -1
- data/spec/cases/{converter_spec.rb → html_page_spec.rb} +18 -7
- data/spec/spec_helper.rb +10 -1
- metadata +7 -6
data/Gemfile
CHANGED
data/Readme.md
CHANGED
@@ -1,11 +1,30 @@
|
|
1
|
-
###
|
1
|
+
### Simple html to Markdown ruby gem
|
2
2
|
We love markdown, cause it is friendly to edit.
|
3
|
-
So we want everything to be markdown
|
3
|
+
So we want everything to be **markdown**
|
4
4
|
|
5
|
-
###
|
5
|
+
### RSpec is our promise
|
6
6
|
```ruby
|
7
7
|
p = HTMLPage.new :contents => '<strong>haha</strong>'
|
8
8
|
p.markdown.should == '**haha**'
|
9
9
|
p.contents = '<strong>hehe</strong>'
|
10
10
|
p.markdown!.should == '**hehe**'
|
11
|
+
|
12
|
+
# you can also define your own node parse
|
13
|
+
p.strong do |node,contents|
|
14
|
+
"strong text : **#{contents}**"
|
15
|
+
end
|
16
|
+
p.markdown!.should be_include('strong text')
|
17
|
+
```
|
18
|
+
|
19
|
+
### Installation
|
20
|
+
* gem
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
gem install html2markdown
|
24
|
+
```
|
25
|
+
|
26
|
+
* Rails Gemfile
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
gem 'html2markdown'
|
11
30
|
```
|
@@ -0,0 +1,545 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://www.kickstarter.com/projects/1397300529/railsapp
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- ! '*/*'
|
12
|
+
User-Agent:
|
13
|
+
- Ruby
|
14
|
+
response:
|
15
|
+
status:
|
16
|
+
code: 200
|
17
|
+
message: OK
|
18
|
+
headers:
|
19
|
+
Server:
|
20
|
+
- nginx/1.0.11
|
21
|
+
Date:
|
22
|
+
- Wed, 28 Mar 2012 23:06:46 GMT
|
23
|
+
Content-Type:
|
24
|
+
- text/html; charset=utf-8
|
25
|
+
Connection:
|
26
|
+
- keep-alive
|
27
|
+
Status:
|
28
|
+
- 200 OK
|
29
|
+
Etag:
|
30
|
+
- ! '"75da5432903c1b163d600fcf81fa65b1"'
|
31
|
+
Set-Cookie:
|
32
|
+
- _ksr_session=BAh7ByIPc2Vzc2lvbl9pZCIlNjhlZGU3NGE3NDQxMWNlMmY4ZDc2NTgyYjk4M2Q1N2QiEF9jc3JmX3Rva2VuIjFLSnV1a1c0RWhLbG12cmQwaVpKVjl1b1VLNHdoSW4rSmJ1Y2J3RmpIMUFjPQ%3D%3D--31eac2c89ed04e369b81ef4dd247fbae2098517e;
|
33
|
+
path=/
|
34
|
+
- abid=BAgiFTk5NDA2OWM4OTY1Y2NhZjI%3D--512e3e9f12894311c8dc10fcb05d3e14f539265c;
|
35
|
+
path=/; expires=Sun, 28-Mar-2032 23:06:46 GMT
|
36
|
+
- last_page=http%3A%2F%2Fwww.kickstarter.com%2Fprojects%2F1397300529%2Frailsapp;
|
37
|
+
path=/; expires=Wed, 28-Mar-2012 23:36:46 GMT
|
38
|
+
- request_time=Wed%2C+28+Mar+2012+23%3A06%3A46+-0000; path=/
|
39
|
+
Content-Length:
|
40
|
+
- '42056'
|
41
|
+
Cache-Control:
|
42
|
+
- max-age=0, private, must-revalidate
|
43
|
+
X-Runtime:
|
44
|
+
- '0.139642'
|
45
|
+
X-Ua-Compatible:
|
46
|
+
- IE=Edge,chrome=1
|
47
|
+
body:
|
48
|
+
encoding: ASCII-8BIT
|
49
|
+
string: ! "<!DOCTYPE html>\n<html class=\"projects_show no-js fontface \" lang=\"en\"
|
50
|
+
xml:lang=\"en\" xmlns:fb=\"http://www.facebook.com/2008/fbml\" xmlns=\"http://www.w3.org/1999/xhtml\">\n<head><script
|
51
|
+
type=\"text/javascript\">var NREUMQ=NREUMQ||[];NREUMQ.push([\"mark\",\"firstbyte\",new
|
52
|
+
Date().getTime()]);</script><title>rails.app by Yehuda Katz — Kickstarter</title><!--[if
|
53
|
+
lt IE 9]>\n <script src=\"http://html5shim.googlecode.com/svn/trunk/html5.js\"
|
54
|
+
type=\"text/javascript\"></script>\n<![endif]-->\n\n\n<meta content=\"text/html;
|
55
|
+
charset=utf-8\" http-equiv=\"Content-Type\">\n<meta content=\"telephone=no\"
|
56
|
+
name=\"format-detection\">\n<link href=\"/fonts/fonts.css\" media=\"screen\"
|
57
|
+
rel=\"stylesheet\" type=\"text/css\">\n<link href=\"http://d297h9he240fqh.cloudfront.net/cache-e1f3b9f54/assets/project_page.css\"
|
58
|
+
media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />\n<!--[if lte IE 7]>\n
|
59
|
+
\ <link href=\"http://d297h9he240fqh.cloudfront.net/cache-e1f3b9f54/stylesheets/compass/library/ie.css\"
|
60
|
+
media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />\n<![endif]-->\n\n<link
|
61
|
+
href=\"http://d297h9he240fqh.cloudfront.net/cache-e1f3b9f54/favicon.png\"
|
62
|
+
rel=\"icon\" type=\"image/png\">\n<link href=\"http://d297h9he240fqh.cloudfront.net/cache-e1f3b9f54/apple-touch-icon-precomposed.png\"
|
63
|
+
rel=\"apple-touch-icon-precomposed\" type=\"image/png\">\n<link href=\"http://d297h9he240fqh.cloudfront.net/cache-e1f3b9f54/apple-touch-icon-ipad-precomposed.png\"
|
64
|
+
rel=\"apple-touch-icon-precomposed\" sizes=\"72x72\" type=\"image/png\">\n<link
|
65
|
+
href=\"http://d297h9he240fqh.cloudfront.net/cache-e1f3b9f54/apple-touch-icon-iphone4-precomposed.png\"
|
66
|
+
rel=\"apple-touch-icon-precomposed\" sizes=\"114x114\" type=\"image/png\">\n<link
|
67
|
+
href=\"http://www.kickstarter.com/services/oembed?url=http%3A%2F%2Fwww.kickstarter.com%2Fprojects%2F1397300529%2Frailsapp\"
|
68
|
+
rel=\"alternate\" title=\"rails.app Script Tag oEmbed\" type=\"application/json+oembed\">\n<link
|
69
|
+
rel=\"alternate\" type=\"application/atom+xml\" title=\"rails.app : Kickstarter\"
|
70
|
+
href=\"http://www.kickstarter.com/projects/1397300529/railsapp/posts.atom\"
|
71
|
+
/>\n<meta name=\"description\" content=\"Yehuda Katz is raising funds for
|
72
|
+
rails.app on Kickstarter! \n\n Let's make Rails on OS X easy again!\n\n"Install
|
73
|
+
this .app. Good job, you now have a working Rails install!"\"/>\n<meta
|
74
|
+
property=\"fb:app_id\" content=\"69103156693\"/>\n<meta property=\"og:type\"
|
75
|
+
content=\"kickstarter:project\"/>\n<meta property=\"kickstarter:location:longitude\"
|
76
|
+
content=\"-122.419\"/>\n<meta property=\"og:image\" content=\"http://s3.amazonaws.com/ksr/projects/82738/photo-full.jpg?1331014996\"/>\n<meta
|
77
|
+
property=\"og:site_name\" content=\"Kickstarter\"/>\n<meta name=\"title\"
|
78
|
+
content=\"Kickstarter >> rails.app by Yehuda Katz\"/>\n<meta property=\"kickstarter:location:latitude\"
|
79
|
+
content=\"37.7749\"/>\n<meta property=\"og:title\" content=\"rails.app\"/>\n<meta
|
80
|
+
property=\"og:description\" content=\"Let's make Rails on OS X easy again!\n\n"Install
|
81
|
+
this .app. Good job, you now have a working Rails install!"\"/>\n<meta
|
82
|
+
property=\"og:url\" content=\"http://www.kickstarter.com/projects/1397300529/railsapp\"/>\n<meta
|
83
|
+
name=\"csrf-param\" content=\"authenticity_token\"/>\n<meta name=\"csrf-token\"
|
84
|
+
content=\"KJuukW4EhKlmvrd0iZJV9uoUK4whIn+JbucbwFjH1Ac=\"/>\n<link href=\"http://kck.st/HfUVql\"
|
85
|
+
rel=\"shorturl\">\n<link href=\"http://www.kickstarter.com/projects/1397300529/railsapp\"
|
86
|
+
rel=\"canonical\">\n<link href=\"http://s3.amazonaws.com/ksr/projects/82738/photo-med.jpg?1331014996\"
|
87
|
+
rel=\"image_src\">\n\n<script>\n //<![CDATA[\n var _sf_startpt=(new Date()).getTime();\n
|
88
|
+
\ docElement = this.document.documentElement;\n docElement.className=docElement.className.replace(/\\bno-js\\b/,'')
|
89
|
+
+ 'js';\n //]]>\n</script>\n<script>\n //<![CDATA[\n function timeRemaining(epochTime){\n
|
90
|
+
\ \n var diff = epochTime - ((new Date()).getTime() / 1000);\n var
|
91
|
+
num_unit = (diff < 60 && [Math.max(diff, 0), 'seconds']) ||\n ((diff/=60)
|
92
|
+
< 60 && [diff, 'minutes']) ||\n ((diff/=60) < 72 && [diff, 'hours'])
|
93
|
+
||\n [diff/=24, 'days'];\n \n // Round down\n num_unit[0]
|
94
|
+
= Math.floor(num_unit[0]);\n // Singularize unit\n if (num_unit[0]
|
95
|
+
== 1) { num_unit[1] = num_unit[1].replace(/s$/,\"\"); }\n \n return
|
96
|
+
num_unit;\n };\n //]]>\n</script>\n</head>\n\n<body class=\"project projects\"
|
97
|
+
id=\"projects_show\">\n<div class=\"jGrowl center\" id=\"growl_section\"></div>\n<div
|
98
|
+
id=\"learn-more-wrap\">\n<div class=\"container\" id=\"learn-more\">\n<p>\n<span
|
99
|
+
class=\"icon-whaaat\"></span>\n<strong>What is Kickstarter?</strong>\nWe’re
|
100
|
+
the world's largest funding platform for creative projects.\n<a href=\"#\"
|
101
|
+
class=\"link_to_learn-more-dialog\">Learn more!</a>\n</p>\n</div>\n</div>\n<div
|
102
|
+
id=\"header-wrap\">\n<div class=\"container\" id=\"header\">\n<h1 id=\"logo\"><a
|
103
|
+
href=\"/\"><span>Kickstarter</span></a></h1>\n<ul id=\"menu-main\">\n<li id=\"menu-main-discover\"><a
|
104
|
+
href=\"/discover\"><strong>Discover</strong> <span>great projects</span></a></li>\n<li
|
105
|
+
id=\"menu-main-fund\"><a href=\"/start\"><strong>Start</strong> <span>your
|
106
|
+
project</span></a></li>\n</ul>\n<form accept-charset=\"UTF-8\" action=\"/projects/search\"
|
107
|
+
class=\"search\" method=\"get\"><div style=\"margin:0;padding:0;display:inline\"><input
|
108
|
+
name=\"utf8\" type=\"hidden\" value=\"✓\" /></div>\n<div class=\"field
|
109
|
+
search\">\n<span class=\"icon-search\"></span>\n<span class=\"icon-search-clear\"></span>\n<input
|
110
|
+
class=\"input-search header text\" data-tracker-name=\"Header Live Search\"
|
111
|
+
id=\"term\" name=\"term\" type=\"text\" />\n<span class=\"icon-search-nipple\"></span>\n</div>\n</form>\n\n<ul
|
112
|
+
id=\"menu-sub\">\n<li id=\"menu-sub-blog\"><a href=\"/blog\">Blog</a></li>\n<li
|
113
|
+
id=\"menu-sub-help\"><a href=\"/help\">Help</a></li>\n<li><a href=\"https://www.kickstarter.com/signup\">Sign
|
114
|
+
up</a></li>\n<li><a href=\"https://www.kickstarter.com/login\">Log in</a></li>\n</ul>\n</div>\n</div>\n<div
|
115
|
+
id=\"search_results-wrap\">\n<div id=\"search_results-shadow\">\n<div id=\"search_results-inner_wrap\">\n<div
|
116
|
+
class=\"container\" id=\"search_results\">\n<a class=\"close\"><span class=\"icon-x\"></span>\nClose</a>\n<h2
|
117
|
+
class=\"header\"></h2>\n<div id=\"search_results_panel\"></div>\n<p class=\"footer\"></p>\n<a
|
118
|
+
class=\"prev arrow\">\n<span class=\"icon-search-left\"></span>\n<strong>Previous</strong>\n</a>\n<a
|
119
|
+
class=\"next arrow\">\n<span class=\"icon-search-right\"></span>\n<strong>Next</strong>\n</a>\n</div>\n</div>\n</div>\n</div>\n\n\n\n\n\n<div
|
120
|
+
id=\"running-board-wrap\">\n<div class=\"container\" id=\"running-board\">\n<div
|
121
|
+
id=\"project-header\">\n<div class=\"NS-project_-running_board\">\n<div id=\"headrow\">\n<h1
|
122
|
+
id=\"name\"><a href=\"/projects/1397300529/railsapp\">rails.app</a></h1>\n<p>\n<span
|
123
|
+
data-project-category=\"Technology\" id=\"project_category\">\nAn\n<a href=\"/discover/categories/Open%20Software?ref=project\">Open
|
124
|
+
Software</a>\n</span>\nproject\nin\n<a href=\"/discover/cities/san-francisco-ca?ref=project\">San
|
125
|
+
Francisco, CA</a>\nby\n<a href=\"/profile/1397300529\" id=\"byline\">Yehuda
|
126
|
+
Katz</a>\n·\n<a href=\"/projects/1397300529/railsapp/messages/new?message[to]=1397300529\"
|
127
|
+
class=\"send-message remote_modal_dialog\" data-modal-title=\"Send a Message
|
128
|
+
to Yehuda Katz\">send message</a>\n</p>\n</div>\n\n<ul id=\"widgets\">\n<li
|
129
|
+
class=\"ajax-container\" id=\"following-widget\">\n<div id=\"follow-tip\">\n<p>Don't
|
130
|
+
want to forget? We'll remind you by email 48 hours before funding ends.</p>\n<span
|
131
|
+
class=\"nipple\"></span>\n</div>\n<div id=\"follow\">\n<a href=\"/projects/1397300529/railsapp/follow\"
|
132
|
+
class=\"button-remind-me\" data-ksrjson=\"true\">Remind Me</a>\n</div>\n\n</li>\n</ul>\n<ul
|
133
|
+
class=\"menu-tabs\" id=\"running-board-nav\">\n<li>\n<a href=\"/projects/1397300529/railsapp\"
|
134
|
+
class=\"current\" id=\"home\">Project Home</a>\n</li>\n<li>\n<a href=\"/projects/1397300529/railsapp/posts\"
|
135
|
+
id=\"updates\">Updates <span class='count'>0</span></a>\n</li>\n<li>\n<a href=\"/projects/1397300529/railsapp/backers\"
|
136
|
+
id=\"backers\">Backers <span class='count'>147</span></a>\n</li>\n<li>\n<a
|
137
|
+
href=\"/projects/1397300529/railsapp/comments\" id=\"comments\">Comments <span
|
138
|
+
class='count'>3</span></a>\n</li>\n</ul>\n</div>\n\n</div>\n</div>\n</div>\n<div
|
139
|
+
id=\"content-wrap\">\n<div class=\"container\" id=\"content\">\n\n<div class=\"NS-projects-content\">\n<div
|
140
|
+
id=\"leftcol\">\n\n<div id=\"video-section\">\n<img alt=\"Photo-full\" src=\"http://s3.amazonaws.com/ksr/projects/82738/photo-full.jpg?1331014996\"
|
141
|
+
/>\n</div>\n<div class=\"share-box-wrap\">\n<table class=\"share-box\">\n<tbody>\n<tr>\n<td
|
142
|
+
class=\"facebook first\">\n<fb:like data-tracker-name=\"Facebook\" font=\"lucida
|
143
|
+
grande\" href=\"http://www.kickstarter.com/projects/1397300529/railsapp\"
|
144
|
+
show_faces=\"false\" width=\"251\"></fb:like>\n</td>\n<td class=\"twitter\">\n<a
|
145
|
+
class=\"twitter-share-button\" data-count=\"none\" data-tracker-name=\"Twitter\"
|
146
|
+
data-url=\"http://kck.st/HfUVql\" data-via=\"kickstarter\" href=\"http://twitter.com/share\"></a>\n</td>\n<td
|
147
|
+
class=\"embed\">\n<a href=\"/projects/1397300529/railsapp/widget\" class=\"button-action
|
148
|
+
remote_modal_dialog\" data-modal-title=\"Embed a widget on your site\" data-tracker-name=\"Embed\"><span
|
149
|
+
class='icon-embed'></span>Embed</a>\n</td>\n<td class=\"short-link\">\n<input
|
150
|
+
class=\"text\" id=\"share_a_link\" name=\"share_a_link\" type=\"text\" value=\"http://kck.st/HfUVql\"
|
151
|
+
/>\n<div class=\"copy_button\">\n<a href=\"\" class=\"copy-button zeroclipboard\"
|
152
|
+
data-text=\"http://kck.st/HfUVql\" data-tracker-name=\"Copy Link\">Copy</a>\n</div>\n</td>\n</tr>\n</tbody>\n</table>\n</div>\n\n<div
|
153
|
+
data-project-state=\"live\" id=\"about\">\n<h3 class=\"dotty\">About this
|
154
|
+
project<div class=\"clear\"></div></h3><p><b>Let's make Rails on OS X easy
|
155
|
+
again!</b></p><p>Getting started with Rails on OS X has gotten hard. When
|
156
|
+
I started working with Rails in 2005, a beginner could get up and running
|
157
|
+
by downloading and running Locomotive. Locomotive made good on the implicit
|
158
|
+
promise of the original <a href=\"http://media.rubyonrails.org/video/rails-0-5.mov\"
|
159
|
+
target=\"_blank\">Get Excited screencast</a>: within minutes, you too can
|
160
|
+
feel the power of Ruby on Rails.</p><p>By the time I became a member of the
|
161
|
+
Rails core team and began work on Rails 3, Locomotive was abandonware. Since
|
162
|
+
OS X shipped with Ruby 1.8, it seemed like a simple `gem install` would do
|
163
|
+
the trick. And for many people, it did.</p><p>Since then, the Ruby ecosystem
|
164
|
+
has become increasingly sophisticated, making tools like bundler and rvm (or
|
165
|
+
rbenv, if that's your thing) a part of the standard workflow. And as those
|
166
|
+
tools increasingly became part of the toolchain for experienced developers,
|
167
|
+
we lost track of the complexity of setting up the standard Ruby toolchain.</p><p>Even
|
168
|
+
more frustrating, every piece of the toolchain has multiple options, meaning
|
169
|
+
that new developers are faced with needing to choose between rvm and rbenv,
|
170
|
+
Ruby 1.8 and Ruby 1.9, etc.</p><p>For experienced developers, these hurdles
|
171
|
+
may not seem particularly large, but they frequently chase away enthusiastic
|
172
|
+
newcomers at exactly the wrong time.</p><p><b>Enough is enough. </b>We need
|
173
|
+
a way to get up and running with Rails that is as conventional and pleasant
|
174
|
+
as Rails itself.</p><p><b>I have a track record of delivering OSS projects.
|
175
|
+
</b>For the past five years, I have worked on a number of popular open source
|
176
|
+
projects. I am probably most well-known for my work on Rails following its
|
177
|
+
merge with Merb, where I was the maintainer.</p><p>My goals for Rails 3 were
|
178
|
+
to bring Merb's ethic of modularity and extensibility to Rails, and Rails
|
179
|
+
3 shipped with a stable plugin API that has paved the way for a richer extension
|
180
|
+
ecosystem. Jose Valim's book, <a href=\"http://pragprog.com/book/jvrails/crafting-rails-applications\"
|
181
|
+
target=\"_blank\">Crafting Rails Applications</a>, illustrates the power of
|
182
|
+
many of these extensions.</p><p>When I began work on Rails 3, the Rails ecosystem
|
183
|
+
desperately needed a stable foundation for long-term extensions. Today, the
|
184
|
+
Rails ecosystem desperately needs to get back to basics and make the experience
|
185
|
+
of starting fresh exciting again.</p><p>I have the track record and skills
|
186
|
+
to deliver a polished, maintainable solution that can become part of the Rails
|
187
|
+
project. Please help me get this done.</p><h1>Deliverables</h1><p>Many of
|
188
|
+
the necessary components for rails.app already exist in some form. <b>I do
|
189
|
+
not want to duplicate existing efforts</b>, where those efforts already solve
|
190
|
+
some part of the larger problem. I will deliver a project that lives in the
|
191
|
+
`rails` organization on GitHub, can be maintained by the Rails team and shipped
|
192
|
+
as part of the official releases.</p><p>My plan is to deliver a `.app` that
|
193
|
+
can be downloaded and dragged to the user's `/Applications` folder. At first,
|
194
|
+
the application will have two facilities:</p><ul>\n<li>Install Rails into
|
195
|
+
the system: This will install a working copy of Ruby, Rubygems, Rails and
|
196
|
+
all necessary gems into the user's system, available from the Terminal. It
|
197
|
+
may also install rvm and other common system tools, depending on the feedback
|
198
|
+
I get from the community as I develop this project.</li>\n<li>Open a Terminal
|
199
|
+
with a working Rails environment: This will leave all necessary resources
|
200
|
+
in the `.app` file or `Application Support`, but open a terminal window with
|
201
|
+
the `$PATH` and other variables set up.</li>\n</ul><p>The second option will
|
202
|
+
be the preferred option for new users, as it will be a more controlled environment
|
203
|
+
with fewer opportunities for something to go wrong. This will not be a toy
|
204
|
+
Ruby. It will be a full-fledged Ruby environment running in an isolated sandbox. <b>My
|
205
|
+
goal is for this mode to be something I personally would use</b>.</p><p>Over
|
206
|
+
time, I imagine that the community would add additional features, such as
|
207
|
+
the ability to start and stop the server, generate files, run migrations,
|
208
|
+
etc. but these are not part of the initial release goals.</p><p>The finished
|
209
|
+
project will also include several facilities to help with long-term maintenance:</p><ul>\n<li>It
|
210
|
+
will prompt the user to accept patch-level updates to Ruby or Rails without
|
211
|
+
requiring a new download of the entire package.</li>\n<li>Each `.app` will
|
212
|
+
be a self-contained environment for a given version of Ruby and Rails, so
|
213
|
+
multiple copies can live side-by-side for users who want to work with, for
|
214
|
+
example, Rails 3.1 and Rails 3.2 for different projects.</li>\n<li>The release
|
215
|
+
of a new version of the `.app` will be fully scripted, working off of release
|
216
|
+
tags of the Rails repository. At the very *most* a single rake task will build
|
217
|
+
and deploy new versions and make those versions available to the `.app`'s
|
218
|
+
updater.</li>\n<li>It will be easy to build a nightly build server for people
|
219
|
+
who want to live on the edge.</li>\n</ul><p>If time permits, I also would
|
220
|
+
like the framework for building this self-contained `.app` to be useful for
|
221
|
+
other projects (such as Compass/Sass) that have a desire to ship self-contained
|
222
|
+
environments for working with Ruby-based tools.</p>\n</div>\n<div class=\"NS-projects-faqs\"
|
223
|
+
id=\"project-faqs\">\n<h3 class=\"dotty hidden\">\nFAQ\n</h3>\n<ul class=\"faqs\">\n\n</ul>\n<div
|
224
|
+
class=\"faq-ask-box\">\n<a href=\"/projects/1397300529/railsapp/messages/new?message[to]=1397300529&mode=FAQ\"
|
225
|
+
class=\"remote_modal_dialog button-neutral\" data-modal-title=\"Ask a question
|
226
|
+
about rails.app\">Ask a question</a>\n<p>\n<strong>Have a question?</strong>\nIf
|
227
|
+
the info above doesn't help, you can ask the project creator directly.\n</p>\n</div>\n</div>\n\n<div
|
228
|
+
id=\"report-issue-wrap\">\n<a href=\"/projects/1397300529/railsapp/report/new\"
|
229
|
+
class=\"remote_modal_dialog\" data-modal-title=\"Report this project to Kickstarter\"
|
230
|
+
id=\"report-issue-link\">Report this project to Kickstarter</a>\n</div>\n</div>\n<div
|
231
|
+
class=\"NS-projects-rightcol\" id=\"rightcol\">\n<div class=\"NS-projects-ecom\"
|
232
|
+
id=\"moneyraised\">\n<h5>\n<div class=\"num\">147</div>\nBackers\n</h5>\n<h5>\n<div
|
233
|
+
class=\"num\">$4,580</div>\npledged of $25,000 goal\n</h5>\n<h5 class=\"ksr_page_timer\"
|
234
|
+
data-end_time=\"Sat, 12 May 2012 16:53:15 -0400\">\n<div class=\"num\"> </div>\n<span
|
235
|
+
class=\"text\"> </span>\n</h5>\n<div id=\"banner\">\nThis project will
|
236
|
+
only be funded if at least $25,000 is pledged by Saturday May 12, 4:53pm
|
237
|
+
EDT.\n</div>\n<div id=\"pledge-wrap\">\n<a href=\"/projects/1397300529/railsapp/pledge/new?clicked_reward=false&logged_in=false&p=0&v=n\"
|
238
|
+
class=\"button roundsmall\" id=\"button-back-this-proj\" title=\"Back This
|
239
|
+
Project\">Back This Project <small>$1 minimum pledge</small></a>\n</div>\n</div>\n\n<div
|
240
|
+
class=\"NS-projects-rightcol-rewards clickable\" id=\"what-you-get\">\n<div
|
241
|
+
class=\"NS-projects-reward clickable\">\n<h3>\n<a href=\"/projects/1397300529/railsapp/pledge/new?backing[amount]=10.0&backing[backer_reward_id]=477812&clicked_reward=true&logged_in=false\">Pledge
|
242
|
+
$10 or more</a>\n<span>Pledge $10 or more</span>\n</h3>\n<div class=\"backers-limits\">\n<span
|
243
|
+
class=\"icon-backer-tag\"></span>\n<span class=\"num-backers\">\n29 Backers\n</span>\n</div>\n<div
|
244
|
+
class=\"desc\">\n<p>Receive a handwritten thank you for sponsoring this project.</p>\n</div>\n<div
|
245
|
+
class=\"delivery-date\">\n<strong>Estimated Delivery:</strong>\nJun 2012\n</div>\n</div>\n<div
|
246
|
+
class=\"NS-projects-reward clickable\">\n<h3>\n<a href=\"/projects/1397300529/railsapp/pledge/new?backing[amount]=25.0&backing[backer_reward_id]=477813&clicked_reward=true&logged_in=false\">Pledge
|
247
|
+
$25 or more</a>\n<span>Pledge $25 or more</span>\n</h3>\n<div class=\"backers-limits\">\n<span
|
248
|
+
class=\"icon-backer-tag\"></span>\n<span class=\"num-backers\">\n61 Backers\n</span>\n</div>\n<div
|
249
|
+
class=\"desc\">\n<p>The previous rewards, plus receive a first-edition backers-only
|
250
|
+
sticker so you can show your support. My laptop is graced with an "I'm
|
251
|
+
committed" sticker that the Rubinius project gave me for my early contributions--this
|
252
|
+
is your chance to spruce up any of your belongings in desperate need of a
|
253
|
+
stickering.</p>\n</div>\n<div class=\"delivery-date\">\n<strong>Estimated
|
254
|
+
Delivery:</strong>\nJul 2012\n</div>\n</div>\n<div class=\"NS-projects-reward
|
255
|
+
clickable\">\n<h3>\n<a href=\"/projects/1397300529/railsapp/pledge/new?backing[amount]=100.0&backing[backer_reward_id]=477814&clicked_reward=true&logged_in=false\">Pledge
|
256
|
+
$100 or more</a>\n<span>Pledge $100 or more</span>\n</h3>\n<div class=\"backers-limits\">\n<span
|
257
|
+
class=\"icon-backer-tag\"></span>\n<span class=\"num-backers\">\n21 Backers\n</span>\n</div>\n<div
|
258
|
+
class=\"desc\">\n<p>The previous rewards, plus access to the internal list
|
259
|
+
for the project, where I'll be soliciting feedback about how to nail this.
|
260
|
+
Great open source projects rarely come from the ideas of just one person,
|
261
|
+
and your input will guarantee that Rails 4 is as great for beginners as it
|
262
|
+
is for experienced developers.</p>\n</div>\n<div class=\"delivery-date\">\n<strong>Estimated
|
263
|
+
Delivery:</strong>\nMay 2012\n</div>\n</div>\n<div class=\"NS-projects-reward
|
264
|
+
clickable\">\n<h3>\n<a href=\"/projects/1397300529/railsapp/pledge/new?backing[amount]=1000.0&backing[backer_reward_id]=477815&clicked_reward=true&logged_in=false\">Pledge
|
265
|
+
$1,000 or more</a>\n<span>Pledge $1,000 or more</span>\n</h3>\n<div class=\"backers-limits\">\n<span
|
266
|
+
class=\"icon-backer-tag\"></span>\n<span class=\"num-backers\">\n0 Backers\n</span>\n<span
|
267
|
+
class=\"limited\">\n• Limited Reward\n(10 of 10 remaining)\n</span>\n</div>\n<div
|
268
|
+
class=\"desc\">\n<p>The previous rewards, plus recognition on the project's
|
269
|
+
website as a backer. If the price is a bit too steep personally, this is a
|
270
|
+
good opportunity to ask your company to contribute to a good cause.</p>\n</div>\n<div
|
271
|
+
class=\"delivery-date\">\n<strong>Estimated Delivery:</strong>\nJul 2012\n</div>\n</div>\n<div
|
272
|
+
class=\"NS-projects-reward clickable\">\n<h3>\n<a href=\"/projects/1397300529/railsapp/pledge/new?backing[amount]=10000.0&backing[backer_reward_id]=550490&clicked_reward=true&logged_in=false\">Pledge
|
273
|
+
$10,000 or more</a>\n<span>Pledge $10,000 or more</span>\n</h3>\n<div class=\"backers-limits\">\n<span
|
274
|
+
class=\"icon-backer-tag\"></span>\n<span class=\"num-backers\">\n0 Backers\n</span>\n<span
|
275
|
+
class=\"limited\">\n• Limited Reward\n(2 of 2 remaining)\n</span>\n</div>\n<div
|
276
|
+
class=\"desc\">\n<p>The previous rewards, plus recognition on the project's
|
277
|
+
website as a sponsor. This recognition will appear above the fold on the front
|
278
|
+
page for at least one year. If you or your company is building a product that
|
279
|
+
appeals to new developers, this is a great way to get some visibility, and
|
280
|
+
give back to the community :D\n\nPing me. Let's talk about how we can both
|
281
|
+
get the most out of this.</p>\n</div>\n<div class=\"delivery-date\">\n<strong>Estimated
|
282
|
+
Delivery:</strong>\nJul 2012\n</div>\n</div>\n\n</div>\n\n<div class=\"NS-projects-rightcol-projectby\"
|
283
|
+
id=\"project-by\">\n<h3 class=\"dotty\">Project By<div class=\"clear\"></div></h3><div
|
284
|
+
id=\"avatar\">\n<a href=\"/profile/1397300529\"><img alt=\"Fb_profile_picture.large\"
|
285
|
+
class=\"avatar-large\" height=\"220\" src=\"http://s3.amazonaws.com/ksr/avatars/441663/fb_profile_picture.large.jpg?1301941659\"
|
286
|
+
width=\"220\" /></a>\n</div>\n<div id=\"creator-details\">\n<h3><a href=\"/profile/1397300529\">Yehuda
|
287
|
+
Katz</a></h3>\n<p class=\"last-login\">\nLast Login\n03/28/12\n</p>\n<ul>\n<li
|
288
|
+
class=\"location\">\n<a href=\"/discover/cities/san-francisco-ca\"><span class='icon'></span>San
|
289
|
+
Francisco, CA</a>\n</li>\n<li class=\"backed\">\n<a href=\"/profiles/1397300529/projects/backed\"
|
290
|
+
class=\"more-button remote_modal_dialog\" data-modal-title=\"Projects backed
|
291
|
+
by Yehuda Katz\"><span class='icon'></span>Backed 2 projects</a>\n</li>\n<li
|
292
|
+
class=\"contactme\">\n<a href=\"/projects/1397300529/railsapp/messages/new?message[to]=1397300529\"
|
293
|
+
class=\"remote_modal_dialog\" data-modal-title=\"Send A Message to Yehuda
|
294
|
+
Katz\"><span class='icon'></span>Send Message</a>\n</li>\n</ul>\n</div>\n<div
|
295
|
+
id=\"facebook-connect\">\n<div class=\"icon\"></div>\n<p>Connected\nas\n<a
|
296
|
+
href=\"http://facebook.com/16200017\" class=\"popup\" target=\"_blank\">Yehuda
|
297
|
+
Katz</a>\n(400 friends)\n</p>\n</div>\n<div id=\"biography\">\n<p>I have
|
298
|
+
a history of working on hard open source projects and delivering on them.</p>\n\n<p>Since
|
299
|
+
2008, I worked on the Merb project, helped lead the Rails 3 effort, and am
|
300
|
+
currently bringing convention over configuration to the browser with Ember.js.</p>\n</div>\n<ol
|
301
|
+
id=\"sites\">\n<li>\n<a href=\"http://www.yehudakatz.com\" class=\"popup\"
|
302
|
+
rel=\"nofollow\" target=\"_blank\">yehudakatz.com</a>\n</li>\n<li>\n<a href=\"http://github.com/wycats\"
|
303
|
+
class=\"popup\" rel=\"nofollow\" target=\"_blank\">github.com</a>\n</li>\n<li>\n<a
|
304
|
+
href=\"http://twitter.com/wycats\" class=\"popup\" rel=\"nofollow\" target=\"_blank\">twitter.com</a>\n</li>\n</ol>\n</div>\n\n</div>\n\n</div>\n\n\n</div>\n</div>\n<div
|
305
|
+
id=\"project_bar\">\n<div class=\"this_project_id\" style=\"display: none;\">82738</div>\n<div
|
306
|
+
class=\"container\">\n<img alt=\"Project_bar_shadow\" class=\"shadow\" src=\"http://d297h9he240fqh.cloudfront.net/cache-e1f3b9f54/images/projects/project_bar_shadow.png\"
|
307
|
+
/>\n<div class=\"window\">\n<ol class=\"projects\">\n<li class=\"page\">\n<ol></ol>\n</li>\n</ol>\n</div>\n<a
|
308
|
+
href=\"#\" class=\"prev arrow enabled\"><div class=\"icon-project-bar-left\"></div>\n</a><a
|
309
|
+
href=\"#\" class=\"next arrow enabled\"><div class=\"icon-project-bar-right\"></div>\n</a></div>\n</div>\n\n\n\n\n<div
|
310
|
+
id=\"mega-footer-wrap\">\n<div id=\"mega-footer-shadow\">\n<div class=\"container\"
|
311
|
+
id=\"mega-footer\">\n<div id=\"mega-discover\">\n<h5>Browse Categories</h5>\n<ul
|
312
|
+
class=\"list-footer-categories list-0\">\n<li><a href=\"/discover/categories/art?ref=footer\">Art</a></li>\n<li><a
|
313
|
+
href=\"/discover/categories/comics?ref=footer\">Comics</a></li>\n<li><a href=\"/discover/categories/dance?ref=footer\">Dance</a></li>\n<li><a
|
314
|
+
href=\"/discover/categories/design?ref=footer\">Design</a></li>\n<li><a href=\"/discover/categories/fashion?ref=footer\">Fashion</a></li>\n<li><a
|
315
|
+
href=\"/discover/categories/film%20&%20video?ref=footer\">Film & Video</a></li>\n<li><a
|
316
|
+
href=\"/discover/categories/food?ref=footer\">Food</a></li>\n</ul>\n<ul class=\"list-footer-categories
|
317
|
+
list-1\">\n<li><a href=\"/discover/categories/games?ref=footer\">Games</a></li>\n<li><a
|
318
|
+
href=\"/discover/categories/music?ref=footer\">Music</a></li>\n<li><a href=\"/discover/categories/photography?ref=footer\">Photography</a></li>\n<li><a
|
319
|
+
href=\"/discover/categories/publishing?ref=footer\">Publishing</a></li>\n<li><a
|
320
|
+
href=\"/discover/categories/technology?ref=footer\">Technology</a></li>\n<li><a
|
321
|
+
href=\"/discover/categories/theater?ref=footer\">Theater</a></li>\n</ul>\n</div>\n<div
|
322
|
+
id=\"mega-join-like\">\n<form accept-charset=\"UTF-8\" action=\"/newsletters/signup\"
|
323
|
+
class=\"overlabels\" method=\"post\"><div style=\"margin:0;padding:0;display:inline\"><input
|
324
|
+
name=\"utf8\" type=\"hidden\" value=\"✓\" /><input name=\"authenticity_token\"
|
325
|
+
type=\"hidden\" value=\"KJuukW4EhKlmvrd0iZJV9uoUK4whIn+JbucbwFjH1Ac=\" /></div>\n<h5>Kickstarter's
|
326
|
+
weekly newsletter</h5>\n<p>Get awesome projects delivered to your inbox each
|
327
|
+
week.</p>\n<textarea class=\"hide textarea\" id=\"comment\" name=\"comment\"></textarea>\n<div
|
328
|
+
class=\"field newsletter\">\n<label class=\"overlabel overlabel-newsletter\">Your
|
329
|
+
email address...</label>\n<input class=\"text\" id=\"email\" name=\"email\"
|
330
|
+
type=\"text\" />\n</div>\n<input class=\"button-positive submit\" id=\"user_submit\"
|
331
|
+
name=\"commit\" type=\"submit\" value=\"Join newsletter\" />\n</form>\n\n<h5>Kickstarter
|
332
|
+
on Facebook</h5>\n<fb:like href=\"http://facebook.com/kickstarter\" show_faces=\"true\"
|
333
|
+
width=\"330\"></fb:like>\n</div>\n<div id=\"mega-connect\">\n<h5>Connect with
|
334
|
+
Kickstarter</h5>\n<ul id=\"list-footer-connect\">\n<li><a href=\"http://twitter.com/kickstarter\"
|
335
|
+
id=\"footer-twitter\"><span class='icon-footer-twitter'></span>Follow on Twitter</a></li>\n<li><a
|
336
|
+
href=\"/blog\" id=\"footer-blog\"><span class='icon-footer-blog'></span>Read
|
337
|
+
our blog</a></li>\n<li><a href=\"/team?ref=footer\" id=\"footer-team\"><span
|
338
|
+
class='icon-footer-team'></span>Meet the team</a></li>\n<li><a href=\"/jobs?ref=footer\"
|
339
|
+
id=\"footer-jobs\"><span class='icon-footer-jobs'></span>Work with us</a></li>\n</ul>\n<span
|
340
|
+
class=\"scissors icon-scissors-1\"></span>\n</div>\n</div>\n</div>\n</div>\n<div
|
341
|
+
id=\"footer-wrap\">\n<div class=\"container\" id=\"footer\">\n<div id=\"etc\">\n<ul>\n<li><a
|
342
|
+
href=\"/help?ref=footer\">Help</a></li>\n<li><a href=\"/help/guidelines?ref=footer\">Guidelines</a></li>\n<li><a
|
343
|
+
href=\"/terms-of-use?ref=footer\">Terms of Use</a></li>\n<li><a href=\"/privacy?ref=footer\">Privacy
|
344
|
+
Policy</a></li>\n<li class=\"last\"><a href=\"http://kickstarter.zendesk.com/home\"
|
345
|
+
id=\"\" onclick=\"Zenbox.render(); return false;\">Contact</a></li>\n</ul>\n</div>\n<div
|
346
|
+
id=\"legal\">\n©\n2012\nKickstarter, Inc.\n</div>\n</div>\n</div>\n\n<script>\n
|
347
|
+
\ //<![CDATA[\n var gaJsHost = ((\"https:\" == document.location.protocol)
|
348
|
+
? \"https://ssl.\" : \"http://www.\");\n document.write(unescape(\"%3Cscript
|
349
|
+
src='\" + gaJsHost + \"google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E\"));\n
|
350
|
+
\ var analytics_vars = { google_analytics_id : \"UA-7621056-1\", logged_in
|
351
|
+
: \"false\", verifying_backing : \"false\" }\n //]]>\n</script>\n\n\n<script>\n
|
352
|
+
\ //<![CDATA[\n _qoptions={qacct:\"p-34IbSpw2K94Sg\"};\n //]]>\n</script>\n<script
|
353
|
+
src=\"http://edge.quantserve.com/quant.js\" type=\"text/javascript\"></script>\n<noscript><img
|
354
|
+
alt=\"Quantcast\" border=\"0\" height=\"1\" src=\"http://pixel.quantserve.com/pixel/p-34IbSpw2K94Sg.gif\"
|
355
|
+
style=\"display:none\" width=\"1\" /></noscript>\n\n<script>\n //<![CDATA[\n
|
356
|
+
\ var _sf_async_config={uid:5536,domain:\"kickstarter.com\"};\n (function(){\n
|
357
|
+
\ function loadChartbeat() {\n window._sf_endpt=(new Date()).getTime();\n
|
358
|
+
\ var e = document.createElement('script');\n e.setAttribute('language',
|
359
|
+
'javascript');\n e.setAttribute('type', 'text/javascript');\n e.setAttribute('src',\n
|
360
|
+
\ ((\"https:\" == document.location.protocol) ? \"https://a248.e.akamai.net/chartbeat.download.akamai.com/102508/\"
|
361
|
+
: \"http://static.chartbeat.com/\") +\n \"js/chartbeat.js\");\n
|
362
|
+
\ document.body.appendChild(e);\n }\n var oldonload = window.onload;\n
|
363
|
+
\ window.onload = (typeof window.onload != 'function') ?\n loadChartbeat
|
364
|
+
: function() { oldonload(); loadChartbeat(); };\n })();\n //]]>\n</script>\n\n<div
|
365
|
+
class=\"modal_dialog\" id=\"learn-more-dialog\" style=\"display: none;\">\n<div
|
366
|
+
class=\"modal_dialog_ie6_background\"></div>\n<div class=\"modal_dialog_outer\">\n<div
|
367
|
+
class=\"modal_dialog_sizer\">\n<div class=\"modal_dialog_inner\">\n<div class=\"modal_dialog_content\">\n<div
|
368
|
+
class=\"modal_dialog_head\"><h4><span>What is Kickstarter?</span></h4><a class=\"modal_dialog_close\"
|
369
|
+
href=\"#\"><span class=\"icon-x\">Close</span></a></div>\n<div class=\"modal_dialog_body\">\n<div
|
370
|
+
id=\"learn-more\">\n<p><strong>Kickstarter is the world's largest funding
|
371
|
+
platform for creative projects.</strong> Every week, tens of thousands of
|
372
|
+
amazing people pledge millions of dollars to projects from the worlds of <span
|
373
|
+
class='category-1'>music</span>, <span class='category-2'>film</span>, <span
|
374
|
+
class='category-3'>art</span>, <span class='category-4'>technology</span>,
|
375
|
+
<span class='category-5'>design</span>, <span class='category-6'>food</span>,
|
376
|
+
<span class='category-7'>publishing</span> and other creative fields.</p>\n<p>\n<strong>A
|
377
|
+
new form of commerce and patronage.</strong>\nThis is not about investment
|
378
|
+
or lending. Project creators keep 100% ownership and control over their work.
|
379
|
+
Instead, they offer products and experiences that are unique to each project.\n</p>\n<p>\n<strong>All
|
380
|
+
or nothing funding.</strong>\nOn Kickstarter, a project must reach its funding
|
381
|
+
goal before time runs out or no money changes hands. Why? It protects everyone
|
382
|
+
involved. Creators aren’t expected to develop their project without necessary
|
383
|
+
funds, and it allows anyone to test concepts without risk.\n</p>\n<p>\n<strong>Each
|
384
|
+
and every project is the independent creation of someone like you.</strong>\nProjects
|
385
|
+
are big and small, serious and whimsical, traditional and experimental. They’re
|
386
|
+
inspiring, entertaining and unbelievably diverse. We hope you agree... Welcome
|
387
|
+
to Kickstarter!\n</p>\n<p><a href=\"#\" class=\"modal_dialog_close\">Thanks!
|
388
|
+
All done.</a></p>\n</div>\n\n</div>\n</div>\n</div>\n<span class=\"modal_dialog_ie_hack\"></span>\n</div>\n</div>\n</div>\n\n<script
|
389
|
+
src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js\" type=\"text/javascript\"></script>\n<script>\n
|
390
|
+
\ //<![CDATA[\n (function () {\n function PageClock(settings){\n this.local_start_time
|
391
|
+
= new Date();\n this.settings = {\n cookie_name : 'request_time'\n
|
392
|
+
\ };\n for (var k in settings) {\n this.settings[k]
|
393
|
+
= settings[k];\n }\n this.get_remote_offset();\n }\n \n
|
394
|
+
\ PageClock.prototype.get_remote_offset = function () {\n // try
|
395
|
+
to get remote time from cookie\n this.cookie_value = this.read_cookie();\n
|
396
|
+
\ var remote_start_time = new Date( this.cookie_value );\n \n if
|
397
|
+
(!this.cookie_value || remote_start_time.toString() === 'Invalid Date') {\n
|
398
|
+
\ // try to get the offset from the local_offset cookie, if present\n
|
399
|
+
\ // this situation arises when the back button is clicked\n this.remote_offset
|
400
|
+
= this.read_cookie('local_offset');\n if (this.remote_offset) {\n
|
401
|
+
\ this.remote_offset = parseInt(this.remote_offset, 10);\n }\n
|
402
|
+
\ } else {\n this.remote_offset = remote_start_time - this.local_start_time;\n
|
403
|
+
\ }\n \n if (typeof this.remote_offset !== 'undefined') {\n
|
404
|
+
\ document.cookie = 'local_offset=' + this.remote_offset + '; path=/';\n
|
405
|
+
\ this.is_set = true;\n } else {\n this.is_set = false;\n
|
406
|
+
\ }\n };\n \n PageClock.prototype.time_units = [\n ['milliseconds',
|
407
|
+
1],\n ['seconds', 1000],\n ['minutes', 1000 * 60],\n ['hours',
|
408
|
+
\ 1000 * 60 * 60],\n ['days', 1000 * 60 * 60 * 24]\n ];\n
|
409
|
+
\ \n PageClock.prototype.get_units_in_interval = function(unit_name,
|
410
|
+
time) {\n var method_name = unit_name.replace(/^\\w/, function(l) {\n
|
411
|
+
\ return 'get' + l.toUpperCase();\n });\n return time[method_name]();\n
|
412
|
+
\ };\n \n PageClock.prototype.milliseconds_in_day = function(time)
|
413
|
+
{\n if (typeof time === 'undefined') {\n time = new Date();\n
|
414
|
+
\ }\n var milliseconds = 0;\n for (var i=this.time_units.length
|
415
|
+
- 2; i >= 0; i--) {\n milliseconds += this.get_units_in_interval(this.time_units[i][0],
|
416
|
+
time) * this.time_units[i][1];\n }\n return milliseconds;\n
|
417
|
+
\ };\n \n PageClock.prototype.milliseconds_in_interval = function(unit_length,
|
418
|
+
time) {\n return this.milliseconds_in_day(time) % unit_length;\n };\n
|
419
|
+
\ \n PageClock.prototype.milliseconds_to_next_interval = function(unit_length,
|
420
|
+
time) {\n return unit_length - this.milliseconds_in_interval(unit_length,
|
421
|
+
time);\n };\n \n PageClock.prototype.pluralize = function(unit,
|
422
|
+
num) {\n if (num === 1) {\n unit = unit.replace(/s$/, '');\n
|
423
|
+
\ }\n return unit;\n };\n \n \n PageClock.prototype.read_cookie
|
424
|
+
= function(cookie_name){\n var\n ca = window.document.cookie.split(';'),\n
|
425
|
+
\ cookie_string = (cookie_name || this.settings.cookie_name) + '=';\n
|
426
|
+
\ for (var i=0;i < ca.length;i++) {\n var c = ca[i];\n while
|
427
|
+
(c.charAt(0)==' ') {\n c = c.substring(1,c.length);\n }\n
|
428
|
+
\ if (c.indexOf(cookie_string) == 0) {\n var encoded_string
|
429
|
+
= c.substring(cookie_string.length,c.length);\n return decodeURIComponent(encoded_string).replace(/\\+/g,
|
430
|
+
' ');\n }\n }\n return null;\n };\n \n PageClock.prototype.destroy_cookie
|
431
|
+
= function() {\n var expires = new Date();\n expires.setTime(expires.getTime()
|
432
|
+
- 1 * 24 * 60 * 60 * 1000);\n window.document.cookie = this.settings.cookie_name
|
433
|
+
+ \"=; expires=\" + expires.toGMTString() + \"; path=/\";\n };\n \n
|
434
|
+
\ PageClock.prototype.get_remote_time = function() {\n var\n time
|
435
|
+
= new Date(),\n remote_milliseconds = time.getTime() + this.remote_offset;\n
|
436
|
+
\ time = time.setTime(remote_milliseconds);\n return time;\n
|
437
|
+
\ };\n \n window.ksr_page_clock = new PageClock();\n })();\n
|
438
|
+
\ \n (function(){\n // simple_find( selector [, context_element]
|
439
|
+
)\n // selector: a string in the form [tag_name].class_name : must include
|
440
|
+
a dot-prefixed css class\n var simple_find = function(selector, context)
|
441
|
+
{\n var\n root = context || window.document.body,\n parts
|
442
|
+
= selector.split('.'),\n class_name = parts[parts.length - 1],\n
|
443
|
+
\ tag_name = (parts.length > 1 && parts[0]) ? parts[0] : '*';\n \n
|
444
|
+
\ if (window.document.getElementsByClassName) {\n return root.getElementsByClassName(class_name);\n
|
445
|
+
\ }\n \n if (root.querySelectorAll) {\n tag_name
|
446
|
+
= tag_name || '';\n return root.querySelectorAll(selector);\n }\n
|
447
|
+
\ \n // lame, fall back\n var\n much_elements = root.getElementsByTagName(tag_name),\n
|
448
|
+
\ elements = [];\n for (var i = 0, much_element; much_element
|
449
|
+
= much_elements[i]; i++) {\n if (this.hasClass(much_element, class_name))
|
450
|
+
{\n elements.push(much_element);\n }\n }\n return
|
451
|
+
elements;\n }\n \n // TODO: decouple this class from the DOM\n
|
452
|
+
\ function ProjectTimer(element, clock, options) {\n this.options
|
453
|
+
= {\n unit_base : {\n 'seconds' : 119,\n 'minutes'
|
454
|
+
: 119,\n 'hours' : 72,\n 'days' : 0\n },\n
|
455
|
+
\ end_phrase : (element.getAttribute('data-word') || 'to go'),\n count_down
|
456
|
+
: false\n };\n for (k in options) {\n this.options[k]
|
457
|
+
= options[k];\n }\n this.clock = clock;\n this.time_units
|
458
|
+
= this.clock.time_units.slice(1);\n this.element = element;\n if
|
459
|
+
(this.clock.is_set) {\n this.attach();\n }\n };\n \n
|
460
|
+
\ ProjectTimer.prototype.get_remaining_time = function() {\n var
|
461
|
+
time = this.remote_end_time - this.clock.get_remote_time();\n if (time
|
462
|
+
< 0) {\n time = 0;\n }\n return time;\n };\n \n
|
463
|
+
\ ProjectTimer.prototype.get_current_unit = function() {\n var
|
464
|
+
unit;\n for (var i=0; i < this.time_units.length; i++) {\n unit
|
465
|
+
= this.time_units[i];\n if (this.get_remaining_time() <= this.options.unit_base[unit[0]]
|
466
|
+
* unit[1]) {\n break;\n }\n }\n return unit;\n
|
467
|
+
\ };\n \n ProjectTimer.prototype.update_element = function() {\n
|
468
|
+
\ var\n unit = this.get_current_unit(),\n number_of_units
|
469
|
+
= Math.floor(this.get_remaining_time() / unit[1]);\n if (isNaN(number_of_units))
|
470
|
+
{ return; }\n this.number_element.innerHTML = number_of_units;\n this.text_element.innerHTML
|
471
|
+
= this.clock.pluralize(unit[0], number_of_units) + ' ' + this.options.end_phrase;\n
|
472
|
+
\ };\n \n ProjectTimer.prototype.valid = function() {\n return
|
473
|
+
!!(this.number_element && this.text_element);\n };\n \n ProjectTimer.prototype.attach
|
474
|
+
= function() {\n function count() {\n timer.update_element();\n
|
475
|
+
\ if (timer.options.count_down && timer.get_remaining_time() > 0)
|
476
|
+
{\n var unit = timer.get_current_unit();\n this.timeout
|
477
|
+
= window.setTimeout(count, timer.clock.milliseconds_to_next_interval(unit[1]));\n
|
478
|
+
\ }\n }\n var timer = this;\n this.remote_end_time_string
|
479
|
+
= this.element.getAttribute('data-end_time');\n this.remote_end_time
|
480
|
+
= new Date(this.remote_end_time_string);\n this.number_element = simple_find('.num',
|
481
|
+
this.element)[0],\n this.text_element = simple_find('.text', this.element)[0],\n
|
482
|
+
\ this.element.ksr_page_timer = true;\n if (this.valid()) {\n
|
483
|
+
\ count();\n }\n };\n \n ProjectTimer.prototype.cancel
|
484
|
+
= function () {\n if (this.timeout) {\n clearTimeout(this.timeout);\n
|
485
|
+
\ }\n };\n \n function TimerFinder() {\n this.elements
|
486
|
+
= [];\n this.attach();\n }\n \n TimerFinder.prototype.loading
|
487
|
+
= true;\n \n TimerFinder.prototype.stop_finding = function() {\n this.attach_timers();\n
|
488
|
+
\ this.loading = false;\n \n if ( document.addEventListener
|
489
|
+
) {\n document.removeEventListener( \"DOMContentLoaded\", this.stop_finding,
|
490
|
+
false );\n } else if ( document.attachEvent ) {\n if ( document.readyState
|
491
|
+
=== \"complete\" ) {\n document.detachEvent( \"onreadystatechange\",
|
492
|
+
this.stop_finding );\n }\n }\n };\n \n TimerFinder.prototype.bind_ready
|
493
|
+
= function() {\n var\n that = this,\n stop_finding
|
494
|
+
= function () {\n that.stop_finding.call(that);\n };\n
|
495
|
+
\ \n // lifted from jQuery's .ready() method:\n // Mozilla,
|
496
|
+
Opera and webkit nightlies currently support this event\n if ( document.addEventListener
|
497
|
+
) {\n // Use the handy event callback\n document.addEventListener(
|
498
|
+
\"DOMContentLoaded\", stop_finding, false );\n \n // A fallback
|
499
|
+
to window.onload, that will always work\n window.addEventListener(
|
500
|
+
\"load\", stop_finding, false );\n \n // If IE event model is used\n
|
501
|
+
\ } else if ( document.attachEvent ) {\n // ensure firing before
|
502
|
+
onload,\n // maybe late but safe also for iframes\n document.attachEvent(
|
503
|
+
\"onreadystatechange\", stop_finding );\n \n // A fallback to
|
504
|
+
window.onload, that will always work\n window.attachEvent( \"onload\",
|
505
|
+
stop_finding );\n }\n };\n \n TimerFinder.prototype.attach_timers
|
506
|
+
= function () {\n var elements = simple_find('div.ksr_page_timer');\n
|
507
|
+
\ for (var i=0; i < elements.length; i++) {\n if (!elements[i].ksr_page_timer)
|
508
|
+
{\n new ProjectTimer(elements[i], window.ksr_page_clock);\n this.elements.push(elements[i]);\n
|
509
|
+
\ }\n }\n };\n \n TimerFinder.prototype.attach
|
510
|
+
= function() {\n var that = this;\n function poll_for_timers()
|
511
|
+
{\n that.attach_timers();\n if (that.loading) {\n window.setTimeout(that.attach_timers,
|
512
|
+
200);\n }\n }\n this.bind_ready();\n poll_for_timers();\n
|
513
|
+
\ };\n \n window.ProjectTimer = ProjectTimer;\n \n new
|
514
|
+
TimerFinder();\n })();\n //]]>\n</script>\n\n<script src=\"http://d297h9he240fqh.cloudfront.net/cache-e1f3b9f54/assets/jwplayer.js\"
|
515
|
+
type=\"text/javascript\"></script>\n<script src=\"http://d297h9he240fqh.cloudfront.net/cache-e1f3b9f54/assets/project_page.js\"
|
516
|
+
type=\"text/javascript\"></script>\n<style type=\"text/css\" media=\"screen,
|
517
|
+
projection\">@import url(http://asset0.zendesk.com/external/zenbox/v2.1/zenbox.css);</style><script
|
518
|
+
type=\"text/javascript\" src=\"http://asset0.zendesk.com/external/zenbox/v2.1/zenbox.js\"></script><script
|
519
|
+
type=\"text/javascript\">\n//<![CDATA[\n if (typeof(Zenbox) !== \"undefined\")
|
520
|
+
{\n Zenbox.init({\n dropboxID: \"20012797\",\n tabID:
|
521
|
+
\"support\",\n hide_tab: true,\n url: \"kickstarter.zendesk.com\"\n
|
522
|
+
\ });\n }\n\n//]]>\n</script>\n<script src=\"http://platform.twitter.com/widgets.js\"
|
523
|
+
type=\"text/javascript\"></script>\n\n\n\n<div id=\"fb-root\"></div>\n<script>\n
|
524
|
+
\ //<![CDATA[\n var channelUrl = window.location.protocol + \"//\" + window.location.host
|
525
|
+
+ \"/channel.html\";\n \n window.fbAsyncInit = function() {\n FB.init({\n
|
526
|
+
\ appId: '69103156693',\n channelUrl: channelUrl,\n status:
|
527
|
+
true, // check login status\n cookie: true, // enable cookies
|
528
|
+
to allow the server to access the session\n xfbml: true, // parse
|
529
|
+
XFBML\n logging: false // turn off logging\n });\n \n $(document).trigger('fb:loaded');\n
|
530
|
+
\ \n var logout_from_fb = false;\n \n FB.Event.subscribe('auth.statusChange',
|
531
|
+
function(response) {\n if (logout_from_fb) {\n FB.logout(function()
|
532
|
+
{\n logout_from_fb = false;\n });\n } else if (response.authResponse
|
533
|
+
&& true && true && true && !FB.usingButton) {\n $.get(\"http://www.kickstarter.com/fb/connect/verify?then=http%3A%2F%2Fwww.kickstarter.com%2Fprojects%2F1397300529%2Frailsapp\",
|
534
|
+
{'fbsr': response.authResponse.signedRequest}, function() {});\n }\n
|
535
|
+
\ });\n \n };\n \n \n // Load the SDK Asynchronously\n
|
536
|
+
\ (function(d){\n var js, id = 'facebook-jssdk'; if (d.getElementById(id))
|
537
|
+
{return;}\n js = d.createElement('script'); js.id = id; js.async = true;\n
|
538
|
+
\ js.src = \"//connect.facebook.net/en_US/all.js\";\n d.getElementsByTagName('head')[0].appendChild(js);\n
|
539
|
+
\ }(document));\n //]]>\n</script>\n\n\n<script type=\"text/javascript\">if
|
540
|
+
(!NREUMQ.f) { NREUMQ.f=function() {\nNREUMQ.push([\"load\",new Date().getTime()]);\nvar
|
541
|
+
e=document.createElement(\"script\");\ne.type=\"text/javascript\";e.async=true;e.src=\"https://d1ros97qkrwjf5.cloudfront.net/30/eum/rum.js\";\ndocument.body.appendChild(e);\nif(NREUMQ.a)NREUMQ.a();\n};\nNREUMQ.a=window.onload;window.onload=NREUMQ.f;\n};\nNREUMQ.push([\"nrfj\",\"beacon-1.newrelic.com\",\"b04b883ad2\",11086,\"cFteRUULX1wHFhtIEFxeVVJDFxxDCgtD\",0.0,120,new
|
542
|
+
Date().getTime(),\"\",\"\",\"\",\"\",\"\"])</script></body>\n</html>\n"
|
543
|
+
http_version: !!null
|
544
|
+
recorded_at: Wed, 28 Mar 2012 23:06:47 GMT
|
545
|
+
recorded_with: VCR 2.0.0
|
data/html2markdown.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |gem|
|
|
6
6
|
gem.email = ["mike.d.1984@gmail.com"]
|
7
7
|
gem.description = %q{simple and flexible html to markdown converter}
|
8
8
|
gem.summary = %q{simple and flexible html to markdown converter}
|
9
|
-
gem.homepage = ""
|
9
|
+
gem.homepage = "https://github.com/29decibel/html2markdown"
|
10
10
|
|
11
11
|
gem.add_dependency 'nokogiri'
|
12
12
|
|
@@ -4,12 +4,15 @@ require_relative '../../lib/html2markdown'
|
|
4
4
|
|
5
5
|
describe HTMLPage do
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
it "should fetch contents of url" do
|
8
|
+
url = 'http://www.kickstarter.com/projects/1397300529/railsapp'
|
9
|
+
VCR.use_cassette 'html_page' do
|
10
|
+
page = HTMLPage.new :url => url
|
11
|
+
page.contents.should_not be_nil
|
12
|
+
page.url.should == url
|
13
|
+
page.markdown.length.should > 0
|
14
|
+
end
|
15
|
+
end
|
13
16
|
|
14
17
|
it "can convert to markdow format" do
|
15
18
|
contents = <<-CON
|
@@ -72,7 +75,6 @@ NEXT!<br>
|
|
72
75
|
end
|
73
76
|
markdown = page.to_markdown page.contents
|
74
77
|
markdown.length.should > 0
|
75
|
-
puts markdown
|
76
78
|
end
|
77
79
|
|
78
80
|
it "should have markdown method" do
|
@@ -81,4 +83,13 @@ NEXT!<br>
|
|
81
83
|
p.contents = '<strong>hehe</strong>'
|
82
84
|
p.markdown!.should == '**hehe**'
|
83
85
|
end
|
86
|
+
|
87
|
+
it "can have custom node parse block" do
|
88
|
+
p = HTMLPage.new :contents => '<strong>haha</strong>'
|
89
|
+
p.strong do |node,contents|
|
90
|
+
"strong text : **#{contents}**"
|
91
|
+
end
|
92
|
+
p.markdown!.should be_include('strong text')
|
93
|
+
end
|
94
|
+
|
84
95
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,6 +4,9 @@ rescue LoadError
|
|
4
4
|
puts 'Although not required, bundler is recommended for running the tests.'
|
5
5
|
end
|
6
6
|
|
7
|
+
require 'vcr'
|
8
|
+
|
9
|
+
# configuration for rspec
|
7
10
|
RSpec.configure do |config|
|
8
11
|
config.mock_with :rspec
|
9
12
|
config.color_enabled = true
|
@@ -19,4 +22,10 @@ RSpec.configure do |config|
|
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
22
|
-
|
25
|
+
# configuration for vcr
|
26
|
+
VCR.configure do |c|
|
27
|
+
c.cassette_library_dir = 'fixtures/vcr_cassettes'
|
28
|
+
c.hook_into :webmock # or :fakeweb
|
29
|
+
end
|
30
|
+
|
31
|
+
require_relative '../lib/html2markdown'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: html2markdown
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-03-28 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
16
|
-
requirement: &
|
16
|
+
requirement: &2155739160 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2155739160
|
25
25
|
description: simple and flexible html to markdown converter
|
26
26
|
email:
|
27
27
|
- mike.d.1984@gmail.com
|
@@ -33,15 +33,16 @@ files:
|
|
33
33
|
- Gemfile
|
34
34
|
- Rakefile
|
35
35
|
- Readme.md
|
36
|
+
- fixtures/vcr_cassettes/html_page.yml
|
36
37
|
- html2markdown.gemspec
|
37
38
|
- lib/html2markdown.rb
|
38
39
|
- lib/html2markdown/converter.rb
|
39
40
|
- lib/html2markdown/exceptions.rb
|
40
41
|
- lib/html2markdown/html_page.rb
|
41
42
|
- lib/html2markdown/version.rb
|
42
|
-
- spec/cases/
|
43
|
+
- spec/cases/html_page_spec.rb
|
43
44
|
- spec/spec_helper.rb
|
44
|
-
homepage:
|
45
|
+
homepage: https://github.com/29decibel/html2markdown
|
45
46
|
licenses: []
|
46
47
|
post_install_message:
|
47
48
|
rdoc_options: []
|
@@ -66,5 +67,5 @@ signing_key:
|
|
66
67
|
specification_version: 3
|
67
68
|
summary: simple and flexible html to markdown converter
|
68
69
|
test_files:
|
69
|
-
- spec/cases/
|
70
|
+
- spec/cases/html_page_spec.rb
|
70
71
|
- spec/spec_helper.rb
|