murlsh 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.htaccess +1 -0
- data/README.textile +11 -8
- data/Rakefile +3 -1
- data/VERSION +1 -1
- data/bin/murlsh +16 -2
- data/config.ru +9 -4
- data/config.yaml +2 -0
- data/lib/murlsh/doc.rb +0 -4
- data/lib/murlsh/flickr_server.rb +3 -4
- data/lib/murlsh/plugin.rb +9 -2
- data/lib/murlsh/twitter_server.rb +3 -4
- data/lib/murlsh/unwrap_jsonp.rb +15 -0
- data/lib/murlsh/uri_ask.rb +6 -3
- data/murlsh.gemspec +14 -7
- data/plugins/add_post_50_update_feed.rb +38 -6
- data/plugins/add_post_50_update_rss.rb +1 -1
- data/plugins/add_post_60_notify_hubs.rb +1 -1
- data/plugins/add_pre_50_lookup_content_type_title.rb +1 -1
- data/plugins/add_pre_60_github_title.rb +1 -1
- data/plugins/hostrec_50_redundant.rb +1 -1
- data/plugins/hostrec_60_skip.rb +5 -4
- data/plugins/html_parse_50_hpricot.rb +19 -0
- data/plugins/time_50_ago.rb +1 -1
- data/plugins/via_50_domain.rb +1 -1
- data/public/css/screen.css +5 -0
- data/public/js/js.js +7 -7
- data/spec/unwrap_json_spec.rb +23 -0
- data/spec/uri_ask_spec.rb +6 -4
- metadata +66 -10
- data/lib/murlsh/atom_feed.rb +0 -84
- data/spec/atom_feed_spec.rb +0 -80
data/.htaccess
CHANGED
data/README.textile
CHANGED
@@ -26,14 +26,8 @@ h2. Phusion Passenger
|
|
26
26
|
<code>
|
27
27
|
gem sources -a http://gemcutter.org/
|
28
28
|
gem install murlsh
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
In the web directory:
|
33
|
-
|
34
|
-
<pre>
|
35
|
-
<code>
|
36
|
-
murlsh
|
29
|
+
murlsh DESTINATION_DIRECTORY
|
30
|
+
cd DESTINATION_DIRECTORY
|
37
31
|
edit config.yaml
|
38
32
|
rake init
|
39
33
|
</code>
|
@@ -56,4 +50,13 @@ pubsubhubbub_hubs:
|
|
56
50
|
publish_url is where the notifications get sent
|
57
51
|
subscribe_url is what gets put in the feed as link rel="hub"
|
58
52
|
|
53
|
+
This will make updates to your feed show up in Google Reader instantly.
|
54
|
+
|
55
|
+
h1. Updating
|
56
|
+
|
57
|
+
If you are using the gem and it gets updated to a new version you should run
|
58
|
+
the murlsh command again from your web directory to update plugins, javascript
|
59
|
+
and css. It will prompt before overwriting anything in case you have made
|
60
|
+
modifications.
|
61
|
+
|
59
62
|
Questions and comments: "matthewm@boedicker.org":mailto:matthewm@boedicker.org
|
data/Rakefile
CHANGED
@@ -303,8 +303,10 @@ begin
|
|
303
303
|
json 1.2.3
|
304
304
|
rack 1.0.0
|
305
305
|
rack-cache 0.5.2
|
306
|
+
rack-throttle 0.3.0
|
306
307
|
sqlite3-ruby 1.2.1
|
307
|
-
|
308
|
+
tinyatom 0.1.1
|
309
|
+
}.each_slice(2) { |g,v| gemspec.add_dependency(g, ">= #{v}") }
|
308
310
|
|
309
311
|
end
|
310
312
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.0
|
data/bin/murlsh
CHANGED
@@ -2,9 +2,18 @@
|
|
2
2
|
|
3
3
|
require 'fileutils'
|
4
4
|
|
5
|
+
def usage
|
6
|
+
puts <<-eos
|
7
|
+
Initialize a murlsh site instance in a web directory.
|
8
|
+
|
9
|
+
usage: murlsh DESTINATION_DIRECTORY
|
10
|
+
|
11
|
+
eos
|
12
|
+
end
|
13
|
+
|
5
14
|
def ask(prompt, default)
|
6
15
|
print "#{prompt} [#{default}] "
|
7
|
-
answer = gets.strip
|
16
|
+
answer = $stdin.gets.strip
|
8
17
|
answer = default if answer.empty?
|
9
18
|
answer
|
10
19
|
end
|
@@ -31,15 +40,20 @@ def cp_r_safe(sources, dest, options)
|
|
31
40
|
|
32
41
|
end
|
33
42
|
|
43
|
+
if ARGV.empty?; usage; exit 1; end
|
44
|
+
|
45
|
+
dest_dir = ARGV[0]
|
46
|
+
|
34
47
|
cp_r_safe(
|
35
48
|
%w{.htaccess config.ru config.yaml plugins/ public/ Rakefile}.map { |x|
|
36
|
-
File.join(File.dirname(__FILE__), '..', x) },
|
49
|
+
File.join(File.dirname(__FILE__), '..', x) }, dest_dir, :verbose => true)
|
37
50
|
|
38
51
|
FileUtils.mkdir_p('tmp', :verbose => true)
|
39
52
|
|
40
53
|
puts <<eos
|
41
54
|
Next steps:
|
42
55
|
|
56
|
+
cd #{dest_dir}
|
43
57
|
edit config.yaml
|
44
58
|
rake init
|
45
59
|
eos
|
data/config.ru
CHANGED
@@ -4,6 +4,7 @@ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
|
4
4
|
yaml
|
5
5
|
|
6
6
|
rack/cache
|
7
|
+
rack/throttle
|
7
8
|
|
8
9
|
murlsh
|
9
10
|
}.each { |m| require m }
|
@@ -11,10 +12,14 @@ murlsh
|
|
11
12
|
config = YAML.load_file('config.yaml')
|
12
13
|
|
13
14
|
# use Rack::ShowExceptions
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
# no more than 1024 requests per day per ip
|
16
|
+
use Rack::Throttle::Daily, :max => 1024
|
17
|
+
if config.key?('cache_metastore') and config.key?('cache_entitystore')
|
18
|
+
use Rack::Cache,
|
19
|
+
:verbose => true,
|
20
|
+
:metastore => config['cache_metastore'],
|
21
|
+
:entitystore => config['cache_entitystore']
|
22
|
+
end
|
18
23
|
use Rack::ConditionalGet
|
19
24
|
use Murlsh::EtagAddEncoding
|
20
25
|
use Rack::Deflater
|
data/config.yaml
CHANGED
data/lib/murlsh/doc.rb
CHANGED
data/lib/murlsh/flickr_server.rb
CHANGED
@@ -2,8 +2,9 @@
|
|
2
2
|
digest/sha1
|
3
3
|
open-uri
|
4
4
|
|
5
|
-
json
|
6
5
|
rack
|
6
|
+
|
7
|
+
murlsh
|
7
8
|
}.each { |m| require m }
|
8
9
|
|
9
10
|
module Murlsh
|
@@ -29,9 +30,7 @@ module Murlsh
|
|
29
30
|
f.read
|
30
31
|
end
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
json_parsed = JSON.parse(json)
|
33
|
+
json_parsed = Murlsh::unwrap_jsonp(json_wrapped)
|
35
34
|
|
36
35
|
resp['Cache-Control'] = 'max-age=86400'
|
37
36
|
resp['Content-Type'] = 'application/json'
|
data/lib/murlsh/plugin.rb
CHANGED
@@ -9,8 +9,12 @@ module Murlsh
|
|
9
9
|
# run arguments (config hash)
|
10
10
|
# * hostrec - called to post process the domain that shows after links
|
11
11
|
# run arguments (domain, url, title)
|
12
|
+
# * html_parse - called to parse HTML using something like Hpricot or Nokogiri
|
13
|
+
# run arguments (parseable)
|
12
14
|
# * time - called to convert the time of a post into a string for display
|
13
15
|
# run arguments (time)
|
16
|
+
# * via - called to convert a via url into a string for display
|
17
|
+
# run arguments (via url)
|
14
18
|
class Plugin
|
15
19
|
|
16
20
|
# Called when a plugin class inherits from this class (the way plugins
|
@@ -21,7 +25,7 @@ module Murlsh
|
|
21
25
|
|
22
26
|
# Get registered plugins by hook (add_pre, add_post, etc.)
|
23
27
|
def self.hooks(name)
|
24
|
-
matches = registered.select { |p| p
|
28
|
+
matches = registered.select { |p| p.hook == name }.
|
25
29
|
sort { |a,b| a.to_s <=> b.to_s }
|
26
30
|
|
27
31
|
if block_given?
|
@@ -31,7 +35,10 @@ module Murlsh
|
|
31
35
|
end
|
32
36
|
|
33
37
|
@registered = []
|
34
|
-
class << self;
|
38
|
+
class << self;
|
39
|
+
attr_reader :hook
|
40
|
+
attr_reader :registered
|
41
|
+
end
|
35
42
|
|
36
43
|
end
|
37
44
|
|
@@ -2,8 +2,9 @@
|
|
2
2
|
digest/sha1
|
3
3
|
open-uri
|
4
4
|
|
5
|
-
json
|
6
5
|
rack
|
6
|
+
|
7
|
+
murlsh
|
7
8
|
}.each { |m| require m }
|
8
9
|
|
9
10
|
module Murlsh
|
@@ -26,9 +27,7 @@ module Murlsh
|
|
26
27
|
f.read
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
json_parsed = JSON.parse(json)
|
30
|
+
json_parsed = Murlsh::unwrap_jsonp(json_wrapped)
|
32
31
|
|
33
32
|
resp['Cache-Control'] = 'max-age=86400'
|
34
33
|
resp['ETag'] = "\"#{Digest::SHA1.hexdigest(json_wrapped)}\""
|
data/lib/murlsh/uri_ask.rb
CHANGED
@@ -4,7 +4,6 @@ net/https
|
|
4
4
|
open-uri
|
5
5
|
uri
|
6
6
|
|
7
|
-
hpricot
|
8
7
|
htmlentities
|
9
8
|
iconv
|
10
9
|
}.each { |m| require m }
|
@@ -76,7 +75,10 @@ module Murlsh
|
|
76
75
|
@description
|
77
76
|
end
|
78
77
|
|
79
|
-
# Get the parsed
|
78
|
+
# Get the parsed doc at this url.
|
79
|
+
#
|
80
|
+
# Doc can be an Hpricot or Nokogiri doc or anything that supports the
|
81
|
+
# methods in Murlsh::Doc.
|
80
82
|
#
|
81
83
|
# Options:
|
82
84
|
# * :failproof - if true hide all exceptions and return empty string on failure
|
@@ -89,7 +91,8 @@ module Murlsh
|
|
89
91
|
if html?(options)
|
90
92
|
Murlsh::failproof(options) do
|
91
93
|
self.open(options[:headers]) do |f|
|
92
|
-
@doc =
|
94
|
+
@doc = Murlsh::Plugin.hooks('html_parse').first.run(f).extend(
|
95
|
+
Murlsh::Doc)
|
93
96
|
|
94
97
|
@charset = @doc.charset || f.charset
|
95
98
|
end
|
data/murlsh.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{murlsh}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.9.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Matthew M. Boedicker"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-06-03}
|
13
13
|
s.default_executable = %q{murlsh}
|
14
14
|
s.description = %q{url sharing site framework with easy adding, title lookup, atom feed, thumbnails and embedding}
|
15
15
|
s.email = %q{matthewm@boedicker.org}
|
@@ -28,7 +28,6 @@ Gem::Specification.new do |s|
|
|
28
28
|
"config.ru",
|
29
29
|
"config.yaml",
|
30
30
|
"lib/murlsh.rb",
|
31
|
-
"lib/murlsh/atom_feed.rb",
|
32
31
|
"lib/murlsh/auth.rb",
|
33
32
|
"lib/murlsh/dispatch.rb",
|
34
33
|
"lib/murlsh/doc.rb",
|
@@ -43,6 +42,7 @@ Gem::Specification.new do |s|
|
|
43
42
|
"lib/murlsh/sqlite3_adapter.rb",
|
44
43
|
"lib/murlsh/time_ago.rb",
|
45
44
|
"lib/murlsh/twitter_server.rb",
|
45
|
+
"lib/murlsh/unwrap_jsonp.rb",
|
46
46
|
"lib/murlsh/uri.rb",
|
47
47
|
"lib/murlsh/uri_ask.rb",
|
48
48
|
"lib/murlsh/url.rb",
|
@@ -58,6 +58,7 @@ Gem::Specification.new do |s|
|
|
58
58
|
"plugins/add_pre_60_github_title.rb",
|
59
59
|
"plugins/hostrec_50_redundant.rb",
|
60
60
|
"plugins/hostrec_60_skip.rb",
|
61
|
+
"plugins/html_parse_50_hpricot.rb",
|
61
62
|
"plugins/time_50_ago.rb",
|
62
63
|
"plugins/via_50_domain.rb",
|
63
64
|
"public/css/jquery.jgrowl.css",
|
@@ -66,11 +67,11 @@ Gem::Specification.new do |s|
|
|
66
67
|
"public/js/jquery.jgrowl_compressed.js",
|
67
68
|
"public/js/js.js",
|
68
69
|
"public/swf/player_mp3_mini.swf",
|
69
|
-
"spec/atom_feed_spec.rb",
|
70
70
|
"spec/auth_spec.rb",
|
71
71
|
"spec/dispatch_spec.rb",
|
72
72
|
"spec/doc_spec.rb",
|
73
73
|
"spec/markup_spec.rb",
|
74
|
+
"spec/unwrap_json_spec.rb",
|
74
75
|
"spec/uri_ask_spec.rb",
|
75
76
|
"spec/uri_spec.rb",
|
76
77
|
"spec/url_spec.rb",
|
@@ -80,13 +81,13 @@ Gem::Specification.new do |s|
|
|
80
81
|
s.homepage = %q{http://github.com/mmb/murlsh}
|
81
82
|
s.rdoc_options = ["--charset=UTF-8"]
|
82
83
|
s.require_paths = ["lib"]
|
83
|
-
s.rubygems_version = %q{1.3.
|
84
|
+
s.rubygems_version = %q{1.3.7}
|
84
85
|
s.summary = %q{url sharing site framework}
|
85
86
|
s.test_files = [
|
86
87
|
"spec/xhtml_response_spec.rb",
|
87
|
-
"spec/atom_feed_spec.rb",
|
88
88
|
"spec/auth_spec.rb",
|
89
89
|
"spec/yaml_ordered_hash_spec.rb",
|
90
|
+
"spec/unwrap_json_spec.rb",
|
90
91
|
"spec/uri_ask_spec.rb",
|
91
92
|
"spec/dispatch_spec.rb",
|
92
93
|
"spec/markup_spec.rb",
|
@@ -99,7 +100,7 @@ Gem::Specification.new do |s|
|
|
99
100
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
100
101
|
s.specification_version = 3
|
101
102
|
|
102
|
-
if Gem::Version.new(Gem::
|
103
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
103
104
|
s.add_runtime_dependency(%q<activerecord>, [">= 2.3.4"])
|
104
105
|
s.add_runtime_dependency(%q<bcrypt-ruby>, [">= 2.1.2"])
|
105
106
|
s.add_runtime_dependency(%q<builder>, [">= 2.1.2"])
|
@@ -108,7 +109,9 @@ Gem::Specification.new do |s|
|
|
108
109
|
s.add_runtime_dependency(%q<json>, [">= 1.2.3"])
|
109
110
|
s.add_runtime_dependency(%q<rack>, [">= 1.0.0"])
|
110
111
|
s.add_runtime_dependency(%q<rack-cache>, [">= 0.5.2"])
|
112
|
+
s.add_runtime_dependency(%q<rack-throttle>, [">= 0.3.0"])
|
111
113
|
s.add_runtime_dependency(%q<sqlite3-ruby>, [">= 1.2.1"])
|
114
|
+
s.add_runtime_dependency(%q<tinyatom>, [">= 0.1.1"])
|
112
115
|
else
|
113
116
|
s.add_dependency(%q<activerecord>, [">= 2.3.4"])
|
114
117
|
s.add_dependency(%q<bcrypt-ruby>, [">= 2.1.2"])
|
@@ -118,7 +121,9 @@ Gem::Specification.new do |s|
|
|
118
121
|
s.add_dependency(%q<json>, [">= 1.2.3"])
|
119
122
|
s.add_dependency(%q<rack>, [">= 1.0.0"])
|
120
123
|
s.add_dependency(%q<rack-cache>, [">= 0.5.2"])
|
124
|
+
s.add_dependency(%q<rack-throttle>, [">= 0.3.0"])
|
121
125
|
s.add_dependency(%q<sqlite3-ruby>, [">= 1.2.1"])
|
126
|
+
s.add_dependency(%q<tinyatom>, [">= 0.1.1"])
|
122
127
|
end
|
123
128
|
else
|
124
129
|
s.add_dependency(%q<activerecord>, [">= 2.3.4"])
|
@@ -129,7 +134,9 @@ Gem::Specification.new do |s|
|
|
129
134
|
s.add_dependency(%q<json>, [">= 1.2.3"])
|
130
135
|
s.add_dependency(%q<rack>, [">= 1.0.0"])
|
131
136
|
s.add_dependency(%q<rack-cache>, [">= 0.5.2"])
|
137
|
+
s.add_dependency(%q<rack-throttle>, [">= 0.3.0"])
|
132
138
|
s.add_dependency(%q<sqlite3-ruby>, [">= 1.2.1"])
|
139
|
+
s.add_dependency(%q<tinyatom>, [">= 0.1.1"])
|
133
140
|
end
|
134
141
|
end
|
135
142
|
|
@@ -1,4 +1,6 @@
|
|
1
1
|
%w{
|
2
|
+
tinyatom
|
3
|
+
|
2
4
|
murlsh
|
3
5
|
}.each { |m| require m }
|
4
6
|
|
@@ -7,18 +9,48 @@ module Murlsh
|
|
7
9
|
# regenerate atom feed after a new url has been added
|
8
10
|
class AddPost50UpdateFeed < Plugin
|
9
11
|
|
10
|
-
|
12
|
+
@hook = 'add_post'
|
11
13
|
|
12
14
|
def self.run(config)
|
15
|
+
feed = TinyAtom::Feed.new(config['root_url'], config.fetch('page_title'),
|
16
|
+
URI.join(config['root_url'], config['feed_file']),
|
17
|
+
:hubs => config.fetch('pubsubhubbub_hubs', []).
|
18
|
+
map { |x| x['subscribe_url'] } )
|
19
|
+
|
13
20
|
latest = Murlsh::Url.all(:order => 'id DESC',
|
14
21
|
:limit => config.fetch('num_posts_feed', 25))
|
15
22
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
latest.each do |mu|
|
24
|
+
options = {
|
25
|
+
:author_name => mu.name,
|
26
|
+
:summary => mu.title_stripped
|
27
|
+
}
|
28
|
+
|
29
|
+
if mu.is_image?
|
30
|
+
options.merge!(
|
31
|
+
:enclosure_type => mu.content_type,
|
32
|
+
:enclosure_href => mu.url,
|
33
|
+
:enclosure_title => 'Full-size'
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
Murlsh::failproof do
|
38
|
+
if mu.via
|
39
|
+
options.merge!(
|
40
|
+
:via_type => 'text/html',
|
41
|
+
:via_href => mu.via,
|
42
|
+
:via_title => URI(mu.via).domain
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
feed.add_entry(mu.id, mu.title_stripped, mu.time, mu.url, options)
|
48
|
+
end
|
49
|
+
|
50
|
+
Murlsh::openlock(config.fetch('feed_file'), 'w') do |f|
|
51
|
+
feed.make(:target => f)
|
52
|
+
end
|
20
53
|
|
21
|
-
feed.write(latest, config.fetch('feed_file'))
|
22
54
|
end
|
23
55
|
|
24
56
|
end
|
data/plugins/hostrec_60_skip.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
module Murlsh
|
2
2
|
|
3
|
-
#
|
3
|
+
# Skip showing host record for some domains.
|
4
4
|
class Hostrec60Skip < Plugin
|
5
5
|
|
6
|
-
|
6
|
+
@hook = 'hostrec'
|
7
7
|
|
8
8
|
def self.run(domain, url, title)
|
9
|
-
domain unless
|
9
|
+
domain unless skips.include?(domain)
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
@skips = %w{
|
13
13
|
wikipedia.org
|
14
14
|
flickr.com
|
15
15
|
github.com
|
@@ -17,6 +17,7 @@ module Murlsh
|
|
17
17
|
vimeo.com
|
18
18
|
youtube.com
|
19
19
|
}
|
20
|
+
class << self; attr_reader :skips; end
|
20
21
|
|
21
22
|
end
|
22
23
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
%w{
|
2
|
+
hpricot
|
3
|
+
}.each { |m| require m }
|
4
|
+
|
5
|
+
module Murlsh
|
6
|
+
|
7
|
+
# Parse HTML with Hpricot and return an Hpricot doc.
|
8
|
+
class HtmlParse50Hpricot < Plugin
|
9
|
+
|
10
|
+
@hook = 'html_parse'
|
11
|
+
|
12
|
+
def self.run(x)
|
13
|
+
Hpricot(x)
|
14
|
+
# Nokogiri(x) also works.
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/plugins/time_50_ago.rb
CHANGED
data/plugins/via_50_domain.rb
CHANGED
data/public/css/screen.css
CHANGED
data/public/js/js.js
CHANGED
@@ -103,7 +103,7 @@ Murlsh.imgThumb = function() {
|
|
103
103
|
|
104
104
|
// if pdf the thumbnail will be .png
|
105
105
|
if (urlParts[lastIndex].match(/^pdf$/i)) {
|
106
|
-
urlParts.lastIndex
|
106
|
+
urlParts.splice(lastIndex, 1, 'png');
|
107
107
|
}
|
108
108
|
|
109
109
|
return Murlsh.img(urlParts.join('')).addClass('thumb');
|
@@ -113,6 +113,10 @@ Murlsh.imgClick = function() {
|
|
113
113
|
Murlsh.closerAdd(Murlsh.img($(this).data('href')));
|
114
114
|
};
|
115
115
|
|
116
|
+
Murlsh.twitterThumb = function(d) {
|
117
|
+
return Murlsh.img(d.user.profile_image_url).addClass('thumb twitter');
|
118
|
+
}
|
119
|
+
|
116
120
|
Murlsh.vimeoThumb = function(d) {
|
117
121
|
return Murlsh.img(d.thumbnail_medium, d.title).addClass('thumb vimeo');
|
118
122
|
};
|
@@ -170,7 +174,7 @@ Murlsh.hrefRes = {
|
|
170
174
|
s3 :
|
171
175
|
/^(http:\/\/static\.mmb\.s3\.amazonaws\.com\/[\w\-]+\.)(jpe?g|gif|pdf|png)$/i,
|
172
176
|
twitter :
|
173
|
-
/^
|
177
|
+
/^https?:\/\/twitter\.com\/\w+\/status(?:es)?\/(\d+)$/i,
|
174
178
|
vimeo :
|
175
179
|
/^http:\/\/(?:www\.)?vimeo\.com\/(\d+)$/i,
|
176
180
|
youtube :
|
@@ -249,11 +253,7 @@ Murlsh.addExtra = function() {
|
|
249
253
|
$(this).html(d.text).before(nameLink).before(
|
250
254
|
document.createTextNode(': '));
|
251
255
|
|
252
|
-
Murlsh.thumbInsert(
|
253
|
-
Murlsh.imgThumb(d.user.profile_image_url).attr({
|
254
|
-
height : '48',
|
255
|
-
width : '48'
|
256
|
-
}), null, nameLink);
|
256
|
+
Murlsh.thumbInsert(Murlsh.twitterThumb(d), null, nameLink);
|
257
257
|
},
|
258
258
|
context : $(this),
|
259
259
|
jsonpCallback : 'twitterCallback' + match.twitter[1]
|
@@ -0,0 +1,23 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
|
3
|
+
%w{
|
4
|
+
murlsh
|
5
|
+
}.each { |m| require m }
|
6
|
+
|
7
|
+
describe Murlsh.method(:unwrap_jsonp) do
|
8
|
+
|
9
|
+
subject do
|
10
|
+
jsonp = <<eos
|
11
|
+
jsonp1270266100192 ({
|
12
|
+
"key" : {
|
13
|
+
"v1" : "value 1",
|
14
|
+
"v2" : "value 2"
|
15
|
+
}
|
16
|
+
}
|
17
|
+
)
|
18
|
+
eos
|
19
|
+
Murlsh::unwrap_jsonp(jsonp)
|
20
|
+
end
|
21
|
+
|
22
|
+
it { should == { 'key' => { 'v1' => 'value 1', 'v2' => 'value 2' } } }
|
23
|
+
end
|
data/spec/uri_ask_spec.rb
CHANGED
@@ -6,6 +6,8 @@ uri
|
|
6
6
|
murlsh
|
7
7
|
}.each { |m| require m }
|
8
8
|
|
9
|
+
Dir['plugins/*.rb'].each { |p| load p }
|
10
|
+
|
9
11
|
describe Murlsh::UriAsk do
|
10
12
|
|
11
13
|
def asker(s)
|
@@ -49,9 +51,9 @@ describe Murlsh::UriAsk do
|
|
49
51
|
content_type('http://x.boedicker.org/', :failproof => true).should be_empty
|
50
52
|
end
|
51
53
|
|
52
|
-
it 'should raise a
|
54
|
+
it 'should raise a NoMethodError when getting the content type of an invalid URI when given failproof option false' do
|
53
55
|
lambda { content_type('http://x.boedicker.org/', :failproof => false)
|
54
|
-
}.should raise_error(
|
56
|
+
}.should raise_error(NoMethodError)
|
55
57
|
end
|
56
58
|
|
57
59
|
it 'should limit redirects when getting content type' do
|
@@ -87,9 +89,9 @@ describe Murlsh::UriAsk do
|
|
87
89
|
).should == 'http://x.boedicker.org/'
|
88
90
|
end
|
89
91
|
|
90
|
-
it 'should raise a
|
92
|
+
it 'should raise a NoMethodError when trying to get the title of an invalid URI when given failproof option false' do
|
91
93
|
lambda { title('http://x.boedicker.org/', :failproof => false)
|
92
|
-
}.should raise_error(
|
94
|
+
}.should raise_error(NoMethodError)
|
93
95
|
end
|
94
96
|
|
95
97
|
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: murlsh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 59
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
8
|
+
- 9
|
9
|
+
- 0
|
10
|
+
version: 0.9.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Matthew M. Boedicker
|
@@ -14,16 +15,18 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-
|
18
|
+
date: 2010-06-03 00:00:00 -04:00
|
18
19
|
default_executable: murlsh
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: activerecord
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 11
|
27
30
|
segments:
|
28
31
|
- 2
|
29
32
|
- 3
|
@@ -35,9 +38,11 @@ dependencies:
|
|
35
38
|
name: bcrypt-ruby
|
36
39
|
prerelease: false
|
37
40
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
38
42
|
requirements:
|
39
43
|
- - ">="
|
40
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 15
|
41
46
|
segments:
|
42
47
|
- 2
|
43
48
|
- 1
|
@@ -49,9 +54,11 @@ dependencies:
|
|
49
54
|
name: builder
|
50
55
|
prerelease: false
|
51
56
|
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
52
58
|
requirements:
|
53
59
|
- - ">="
|
54
60
|
- !ruby/object:Gem::Version
|
61
|
+
hash: 15
|
55
62
|
segments:
|
56
63
|
- 2
|
57
64
|
- 1
|
@@ -63,9 +70,11 @@ dependencies:
|
|
63
70
|
name: hpricot
|
64
71
|
prerelease: false
|
65
72
|
requirement: &id004 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
66
74
|
requirements:
|
67
75
|
- - ">="
|
68
76
|
- !ruby/object:Gem::Version
|
77
|
+
hash: 61
|
69
78
|
segments:
|
70
79
|
- 0
|
71
80
|
- 8
|
@@ -77,9 +86,11 @@ dependencies:
|
|
77
86
|
name: htmlentities
|
78
87
|
prerelease: false
|
79
88
|
requirement: &id005 !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
80
90
|
requirements:
|
81
91
|
- - ">="
|
82
92
|
- !ruby/object:Gem::Version
|
93
|
+
hash: 55
|
83
94
|
segments:
|
84
95
|
- 4
|
85
96
|
- 2
|
@@ -91,9 +102,11 @@ dependencies:
|
|
91
102
|
name: json
|
92
103
|
prerelease: false
|
93
104
|
requirement: &id006 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
94
106
|
requirements:
|
95
107
|
- - ">="
|
96
108
|
- !ruby/object:Gem::Version
|
109
|
+
hash: 25
|
97
110
|
segments:
|
98
111
|
- 1
|
99
112
|
- 2
|
@@ -105,9 +118,11 @@ dependencies:
|
|
105
118
|
name: rack
|
106
119
|
prerelease: false
|
107
120
|
requirement: &id007 !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
108
122
|
requirements:
|
109
123
|
- - ">="
|
110
124
|
- !ruby/object:Gem::Version
|
125
|
+
hash: 23
|
111
126
|
segments:
|
112
127
|
- 1
|
113
128
|
- 0
|
@@ -119,9 +134,11 @@ dependencies:
|
|
119
134
|
name: rack-cache
|
120
135
|
prerelease: false
|
121
136
|
requirement: &id008 !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
122
138
|
requirements:
|
123
139
|
- - ">="
|
124
140
|
- !ruby/object:Gem::Version
|
141
|
+
hash: 15
|
125
142
|
segments:
|
126
143
|
- 0
|
127
144
|
- 5
|
@@ -130,19 +147,53 @@ dependencies:
|
|
130
147
|
type: :runtime
|
131
148
|
version_requirements: *id008
|
132
149
|
- !ruby/object:Gem::Dependency
|
133
|
-
name:
|
150
|
+
name: rack-throttle
|
134
151
|
prerelease: false
|
135
152
|
requirement: &id009 !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
136
154
|
requirements:
|
137
155
|
- - ">="
|
138
156
|
- !ruby/object:Gem::Version
|
157
|
+
hash: 19
|
158
|
+
segments:
|
159
|
+
- 0
|
160
|
+
- 3
|
161
|
+
- 0
|
162
|
+
version: 0.3.0
|
163
|
+
type: :runtime
|
164
|
+
version_requirements: *id009
|
165
|
+
- !ruby/object:Gem::Dependency
|
166
|
+
name: sqlite3-ruby
|
167
|
+
prerelease: false
|
168
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
hash: 29
|
139
174
|
segments:
|
140
175
|
- 1
|
141
176
|
- 2
|
142
177
|
- 1
|
143
178
|
version: 1.2.1
|
144
179
|
type: :runtime
|
145
|
-
version_requirements: *
|
180
|
+
version_requirements: *id010
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: tinyatom
|
183
|
+
prerelease: false
|
184
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
hash: 25
|
190
|
+
segments:
|
191
|
+
- 0
|
192
|
+
- 1
|
193
|
+
- 1
|
194
|
+
version: 0.1.1
|
195
|
+
type: :runtime
|
196
|
+
version_requirements: *id011
|
146
197
|
description: url sharing site framework with easy adding, title lookup, atom feed, thumbnails and embedding
|
147
198
|
email: matthewm@boedicker.org
|
148
199
|
executables:
|
@@ -162,7 +213,6 @@ files:
|
|
162
213
|
- config.ru
|
163
214
|
- config.yaml
|
164
215
|
- lib/murlsh.rb
|
165
|
-
- lib/murlsh/atom_feed.rb
|
166
216
|
- lib/murlsh/auth.rb
|
167
217
|
- lib/murlsh/dispatch.rb
|
168
218
|
- lib/murlsh/doc.rb
|
@@ -177,6 +227,7 @@ files:
|
|
177
227
|
- lib/murlsh/sqlite3_adapter.rb
|
178
228
|
- lib/murlsh/time_ago.rb
|
179
229
|
- lib/murlsh/twitter_server.rb
|
230
|
+
- lib/murlsh/unwrap_jsonp.rb
|
180
231
|
- lib/murlsh/uri.rb
|
181
232
|
- lib/murlsh/uri_ask.rb
|
182
233
|
- lib/murlsh/url.rb
|
@@ -192,6 +243,7 @@ files:
|
|
192
243
|
- plugins/add_pre_60_github_title.rb
|
193
244
|
- plugins/hostrec_50_redundant.rb
|
194
245
|
- plugins/hostrec_60_skip.rb
|
246
|
+
- plugins/html_parse_50_hpricot.rb
|
195
247
|
- plugins/time_50_ago.rb
|
196
248
|
- plugins/via_50_domain.rb
|
197
249
|
- public/css/jquery.jgrowl.css
|
@@ -200,11 +252,11 @@ files:
|
|
200
252
|
- public/js/jquery.jgrowl_compressed.js
|
201
253
|
- public/js/js.js
|
202
254
|
- public/swf/player_mp3_mini.swf
|
203
|
-
- spec/atom_feed_spec.rb
|
204
255
|
- spec/auth_spec.rb
|
205
256
|
- spec/dispatch_spec.rb
|
206
257
|
- spec/doc_spec.rb
|
207
258
|
- spec/markup_spec.rb
|
259
|
+
- spec/unwrap_json_spec.rb
|
208
260
|
- spec/uri_ask_spec.rb
|
209
261
|
- spec/uri_spec.rb
|
210
262
|
- spec/url_spec.rb
|
@@ -220,31 +272,35 @@ rdoc_options:
|
|
220
272
|
require_paths:
|
221
273
|
- lib
|
222
274
|
required_ruby_version: !ruby/object:Gem::Requirement
|
275
|
+
none: false
|
223
276
|
requirements:
|
224
277
|
- - ">="
|
225
278
|
- !ruby/object:Gem::Version
|
279
|
+
hash: 3
|
226
280
|
segments:
|
227
281
|
- 0
|
228
282
|
version: "0"
|
229
283
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
284
|
+
none: false
|
230
285
|
requirements:
|
231
286
|
- - ">="
|
232
287
|
- !ruby/object:Gem::Version
|
288
|
+
hash: 3
|
233
289
|
segments:
|
234
290
|
- 0
|
235
291
|
version: "0"
|
236
292
|
requirements: []
|
237
293
|
|
238
294
|
rubyforge_project:
|
239
|
-
rubygems_version: 1.3.
|
295
|
+
rubygems_version: 1.3.7
|
240
296
|
signing_key:
|
241
297
|
specification_version: 3
|
242
298
|
summary: url sharing site framework
|
243
299
|
test_files:
|
244
300
|
- spec/xhtml_response_spec.rb
|
245
|
-
- spec/atom_feed_spec.rb
|
246
301
|
- spec/auth_spec.rb
|
247
302
|
- spec/yaml_ordered_hash_spec.rb
|
303
|
+
- spec/unwrap_json_spec.rb
|
248
304
|
- spec/uri_ask_spec.rb
|
249
305
|
- spec/dispatch_spec.rb
|
250
306
|
- spec/markup_spec.rb
|
data/lib/murlsh/atom_feed.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
%w{
|
2
|
-
uri
|
3
|
-
|
4
|
-
builder
|
5
|
-
}.each { |m| require m }
|
6
|
-
|
7
|
-
module Murlsh
|
8
|
-
|
9
|
-
# ATOM feed builder.
|
10
|
-
class AtomFeed
|
11
|
-
|
12
|
-
# root_url is the base url for the feed items.
|
13
|
-
#
|
14
|
-
# Options:
|
15
|
-
# * :filename - the file name of the feed (atom.xml)
|
16
|
-
# * :title - the feed title
|
17
|
-
def initialize(root_url, options={})
|
18
|
-
options = {
|
19
|
-
:filename => 'atom.xml',
|
20
|
-
:title => 'Atom feed',
|
21
|
-
:hubs => []}.merge(options)
|
22
|
-
@root_url = root_url
|
23
|
-
@filename = options[:filename]
|
24
|
-
@title = options[:title]
|
25
|
-
@hubs = options[:hubs]
|
26
|
-
|
27
|
-
root_uri = URI(@root_url)
|
28
|
-
|
29
|
-
@host, @domain, @path = root_uri.host, root_uri.domain, root_uri.path
|
30
|
-
end
|
31
|
-
|
32
|
-
# Generate the feed and write it to the filesystem with locking.
|
33
|
-
def write(entries, path)
|
34
|
-
Murlsh::openlock(path, 'w') { |f| make(entries, :target => f) }
|
35
|
-
end
|
36
|
-
|
37
|
-
# Build the feed using XML builder. Options are passed to
|
38
|
-
# Builder::XmlMarkup.new.
|
39
|
-
def make(entries, options={})
|
40
|
-
xm = Builder::XmlMarkup.new(options)
|
41
|
-
xm.instruct!(:xml)
|
42
|
-
|
43
|
-
xm.feed(:xmlns => 'http://www.w3.org/2005/Atom') {
|
44
|
-
xm.id(@root_url)
|
45
|
-
xm.link(:href => URI.join(@root_url, @filename), :rel => 'self')
|
46
|
-
@hubs.each { |hub| xm.link(:href => hub, :rel => 'hub') }
|
47
|
-
xm.title(@title)
|
48
|
-
xm.updated(entries.map(&:time).max.xmlschema)
|
49
|
-
entries.each do |mu|
|
50
|
-
xm.entry {
|
51
|
-
xm.author { xm.name(mu.name) }
|
52
|
-
xm.title(mu.title_stripped)
|
53
|
-
xm.id(entry_id(mu))
|
54
|
-
xm.summary(mu.title_stripped)
|
55
|
-
xm.updated(mu.time.xmlschema)
|
56
|
-
xm.link(:href => mu.url)
|
57
|
-
enclosure(xm, mu)
|
58
|
-
via(xm, mu)
|
59
|
-
}
|
60
|
-
end
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
|
-
# Build the entry's id.
|
65
|
-
def entry_id(url)
|
66
|
-
"tag:#{@domain},#{url.time.strftime('%Y-%m-%d')}:#{@host}#{@path}#{url.id}"
|
67
|
-
end
|
68
|
-
|
69
|
-
# Add an ATOM enclosure if the url is an image.
|
70
|
-
def enclosure(xm, mu)
|
71
|
-
xm.link(:rel => 'enclosure', :type => mu.content_type, :href => mu.url,
|
72
|
-
:title => 'Full-size') if mu.is_image?
|
73
|
-
end
|
74
|
-
|
75
|
-
def via(xm, mu)
|
76
|
-
Murlsh::failproof do
|
77
|
-
xm.link(:rel => 'via', :type => 'text/html', :href => mu.via,
|
78
|
-
:title => URI(mu.via).domain) if mu.via
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
data/spec/atom_feed_spec.rb
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
-
|
3
|
-
%w{
|
4
|
-
tempfile
|
5
|
-
time
|
6
|
-
|
7
|
-
murlsh
|
8
|
-
}.each { |m| require m }
|
9
|
-
|
10
|
-
describe Murlsh::AtomFeed do
|
11
|
-
|
12
|
-
before do
|
13
|
-
@url1 = stub('Url',
|
14
|
-
:content_type => 'text/html',
|
15
|
-
:id => 1,
|
16
|
-
:is_image? => false,
|
17
|
-
:name => 'test 1',
|
18
|
-
:time => Time.parse('dec 19 2009 12:34:56pm').utc,
|
19
|
-
:title_stripped => 'test title',
|
20
|
-
:url => 'http://matthewm.boedicker.org/',
|
21
|
-
:via => 'http://www.google.com')
|
22
|
-
|
23
|
-
@url2 = stub('Url',
|
24
|
-
:content_type => 'image/jpeg',
|
25
|
-
:id => 2,
|
26
|
-
:is_image? => true,
|
27
|
-
:name => 'test 2',
|
28
|
-
:time => Time.parse('dec 20 2009 10:10:10am').utc,
|
29
|
-
:title_stripped => 'image test',
|
30
|
-
:url => 'http://matthewm.boedicker.org/test.jpg',
|
31
|
-
:via => nil)
|
32
|
-
|
33
|
-
@feed = Murlsh::AtomFeed.new('http://test.com/test/', :title => 'test')
|
34
|
-
|
35
|
-
@expected = Regexp.new(<<EOS, Regexp::MULTILINE)
|
36
|
-
<\\?xml version="1\.0" encoding="UTF-8"\\?>
|
37
|
-
<feed xmlns="http://www\\.w3\\.org/2005/Atom">
|
38
|
-
<id>http://test\\.com/test/</id>
|
39
|
-
<link href="http://test\\.com/test/atom\\.xml" rel="self"/>
|
40
|
-
<title>test</title>
|
41
|
-
<updated>2009-12-20T15:10:10Z</updated>
|
42
|
-
<entry>
|
43
|
-
<author>
|
44
|
-
<name>test 1</name>
|
45
|
-
</author>
|
46
|
-
<title>test title</title>
|
47
|
-
<id>tag:test\\.com,2009-12-19:test\\.com/test/1</id>
|
48
|
-
<summary>test title</summary>
|
49
|
-
<updated>2009-12-19T17:34:56Z</updated>
|
50
|
-
<link href="http://matthewm\\.boedicker\\.org/"/>
|
51
|
-
<link type=".*"/>
|
52
|
-
</entry>
|
53
|
-
<entry>
|
54
|
-
<author>
|
55
|
-
<name>test 2</name>
|
56
|
-
</author>
|
57
|
-
<title>image test</title>
|
58
|
-
<id>tag:test\\.com,2009-12-20:test\\.com/test/2</id>
|
59
|
-
<summary>image test</summary>
|
60
|
-
<updated>2009-12-20T15:10:10Z</updated>
|
61
|
-
<link href="http://matthewm\\.boedicker\\.org/test\\.jpg"/>
|
62
|
-
<link type=".*"/>
|
63
|
-
</entry>
|
64
|
-
</feed>
|
65
|
-
EOS
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'should generate the correct atom feed' do
|
70
|
-
@feed.make([@url1, @url2], :indent => 2).should match @expected
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'should write the correct atom feed to a file' do
|
74
|
-
tempfile = Tempfile.open('test_atom_feed')
|
75
|
-
@feed.make([@url1, @url2], :indent => 2, :target => tempfile)
|
76
|
-
|
77
|
-
open(tempfile) { |f| f.read.should match @expected }
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|