murlsh 0.6.1 → 0.7.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/.gitignore +3 -0
- data/README.textile +25 -2
- data/Rakefile +37 -5
- data/VERSION +1 -1
- data/bin/murlsh +3 -3
- data/config.ru +10 -4
- data/config.yaml +14 -10
- data/lib/murlsh/atom_feed.rb +5 -4
- data/lib/murlsh/auth.rb +6 -7
- data/lib/murlsh/dispatch.rb +25 -23
- data/lib/murlsh/doc.rb +14 -6
- data/lib/murlsh/etag_add_encoding.rb +27 -0
- data/lib/murlsh/flickr_server.rb +54 -0
- data/lib/murlsh/markup.rb +18 -1
- data/lib/murlsh/plugin.rb +2 -0
- data/lib/murlsh/sqlite3_adapter.rb +3 -1
- data/lib/murlsh/time_ago.rb +27 -0
- data/lib/murlsh/uri.rb +3 -1
- data/lib/murlsh/uri_ask.rb +13 -10
- data/lib/murlsh/url.rb +11 -4
- data/lib/murlsh/url_body.rb +21 -31
- data/lib/murlsh/url_server.rb +1 -2
- data/lib/murlsh/yaml_ordered_hash.rb +22 -0
- data/lib/murlsh.rb +4 -18
- data/murlsh.gemspec +22 -5
- data/plugins/add_post_50_update_feed.rb +4 -2
- data/plugins/add_post_50_update_rss.rb +37 -0
- data/plugins/add_post_60_notify_hubs.rb +3 -2
- data/plugins/add_pre_50_lookup_content_type_title.rb +3 -1
- data/plugins/time_50_ago.rb +16 -0
- data/plugins/via_50_domain.rb +36 -0
- data/public/css/screen.css +5 -6
- data/public/js/js.js +142 -94
- data/spec/atom_feed_spec.rb +21 -20
- data/spec/auth_spec.rb +8 -6
- data/spec/dispatch_spec.rb +26 -0
- data/spec/doc_spec.rb +27 -0
- data/spec/markup_spec.rb +3 -1
- data/spec/uri_ask_spec.rb +5 -3
- data/spec/uri_spec.rb +3 -1
- data/spec/url_spec.rb +52 -0
- data/spec/xhtml_response_spec.rb +3 -1
- data/spec/yaml_ordered_hash_spec.rb +28 -0
- metadata +37 -9
- data/lib/murlsh/time.rb +0 -20
data/lib/murlsh/url_body.rb
CHANGED
@@ -20,7 +20,7 @@ module Murlsh
|
|
20
20
|
def search_conditions
|
21
21
|
if @q
|
22
22
|
search_cols = %w{name title url}
|
23
|
-
[search_cols.
|
23
|
+
[search_cols.map { |x| "MATCH(#{x}, ?)" }.join(' OR ')].push(
|
24
24
|
*[@q] * search_cols.size)
|
25
25
|
else
|
26
26
|
[]
|
@@ -51,21 +51,26 @@ module Murlsh
|
|
51
51
|
div(:class => 'icon') {
|
52
52
|
gravatar(mu.email, 's' => gravatar_size, :text => mu.name)
|
53
53
|
} if mu.email and gravatar_size > 0
|
54
|
-
div(mu.name, :class => 'name') if
|
54
|
+
div(mu.name, :class => 'name') if
|
55
|
+
@config.fetch('show_names', false) and mu.name
|
55
56
|
end
|
56
57
|
|
57
|
-
a(mu.title_stripped, :href => mu.url)
|
58
|
+
a(mu.title_stripped, :href => mu.url, :class => 'm')
|
58
59
|
|
59
60
|
mu.hostrec do |hostrec|
|
60
61
|
self.span(" [#{hostrec}]", :class => 'host')
|
61
62
|
end
|
62
63
|
mu.viarec do |via|
|
64
|
+
display_via = Murlsh::Plugin.hooks('via').inject(
|
65
|
+
via) { |result,plugin| plugin.run(result) }
|
63
66
|
span(:class => 'via') {
|
64
|
-
text!(' via '); a(
|
67
|
+
text!(' via '); a(display_via, :href => via)
|
65
68
|
}
|
66
69
|
end
|
67
|
-
|
68
|
-
|
70
|
+
|
71
|
+
display_time = Murlsh::Plugin.hooks('time').inject(
|
72
|
+
mu.time) { |result,plugin| plugin.run(result) }
|
73
|
+
span(", #{display_time}", :class => 'date') if display_time
|
69
74
|
last = mu
|
70
75
|
}
|
71
76
|
end
|
@@ -85,10 +90,8 @@ module Murlsh
|
|
85
90
|
def headd
|
86
91
|
head {
|
87
92
|
titlee
|
88
|
-
metas(
|
89
|
-
|
90
|
-
'width=device-width,minimum-scale=1.0,maximum-scale=1.0')
|
91
|
-
google_verify
|
93
|
+
metas(@config.select { |k,v| k =~ /^meta_tag_/ and v }.
|
94
|
+
map { |k,v| [k.sub('meta_tag_', ''), v] })
|
92
95
|
css(@config['css_compressed'] || @config['css_files'])
|
93
96
|
atom(@config.fetch('feed_file'))
|
94
97
|
}
|
@@ -99,11 +102,6 @@ module Murlsh
|
|
99
102
|
title(@config.fetch('page_title', '') + (@q ? " /#{@q}" : ''))
|
100
103
|
end
|
101
104
|
|
102
|
-
# Google verification link builder.
|
103
|
-
def google_verify
|
104
|
-
(gv = @config.fetch('google_verify')) and metas('verify-v1' => gv)
|
105
|
-
end
|
106
|
-
|
107
105
|
# Feed icon builder.
|
108
106
|
def feed_icon
|
109
107
|
div(:class => 'icon') {
|
@@ -115,9 +113,8 @@ module Murlsh
|
|
115
113
|
def search_form
|
116
114
|
form(:action => '', :method => 'get') {
|
117
115
|
fieldset {
|
118
|
-
|
119
|
-
|
120
|
-
input(:type => 'submit', :value=> 'Regex Search')
|
116
|
+
form_input(:id => 'q', :size => 32, :value => @q)
|
117
|
+
form_input(:type => 'submit', :value => 'Regex Search')
|
121
118
|
}
|
122
119
|
}
|
123
120
|
end
|
@@ -126,26 +123,19 @@ module Murlsh
|
|
126
123
|
def add_form
|
127
124
|
form(:action => '', :method => 'post') {
|
128
125
|
fieldset(:id => 'add') {
|
129
|
-
self.p {
|
130
|
-
self.p {
|
126
|
+
self.p { form_input(:id => 'url', :label => 'Add URL', :size => 32) }
|
127
|
+
self.p { form_input(:id => 'via', :label => 'Via', :size => 32) }
|
131
128
|
self.p {
|
132
|
-
|
133
|
-
|
129
|
+
form_input(:id => 'auth', :label => 'Password', :size => 16,
|
130
|
+
:type => 'password')
|
131
|
+
form_input(:id => 'submit', :type => 'button', :value => 'Add')
|
134
132
|
}
|
135
133
|
}
|
136
134
|
}
|
137
135
|
end
|
138
136
|
|
139
|
-
# Url add form input builder.
|
140
|
-
def add_form_input(label, id, size, tipe='text')
|
141
|
-
label(label, :for => id)
|
142
|
-
input(:type => tipe, :id => id, :name => id, :size => size)
|
143
|
-
end
|
144
|
-
|
145
137
|
# Clear div builder.
|
146
|
-
def clear
|
147
|
-
div(:style => 'clear : both')
|
148
|
-
end
|
138
|
+
def clear; div(:style => 'clear : both'); end
|
149
139
|
|
150
140
|
# Powered by builder.
|
151
141
|
def powered_by
|
data/lib/murlsh/url_server.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
%w{
|
2
|
-
rubygems
|
3
2
|
active_record
|
4
3
|
rack
|
5
4
|
}.each { |m| require m }
|
@@ -25,7 +24,7 @@ module Murlsh
|
|
25
24
|
|
26
25
|
last_db_update = File::Stat.new(@config['db_file']).mtime
|
27
26
|
resp['Last-Modified'] = last_db_update.httpdate
|
28
|
-
resp['ETag'] = "#{last_db_update.to_i}#{req.params.sort}"
|
27
|
+
resp['ETag'] = "W/\"#{last_db_update.to_i}#{req.params.sort}\""
|
29
28
|
|
30
29
|
resp.body = Murlsh::UrlBody.new(@config, @db, req)
|
31
30
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
%w{
|
2
|
+
yaml
|
3
|
+
}.each { |m| require m }
|
4
|
+
|
5
|
+
module Murlsh
|
6
|
+
|
7
|
+
# Hash mixin to generate yaml with hash keys in sorted order.
|
8
|
+
module YamlOrderedHash
|
9
|
+
|
10
|
+
def to_yaml(opts={})
|
11
|
+
YAML::quick_emit(self, opts) do |out|
|
12
|
+
out.map(taguri, to_yaml_style) do |map|
|
13
|
+
sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |k, v|
|
14
|
+
map.add( k, v )
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/murlsh.rb
CHANGED
@@ -1,18 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require
|
5
|
-
require 'murlsh/failproof'
|
6
|
-
require 'murlsh/openlock'
|
7
|
-
require 'murlsh/plugin'
|
8
|
-
require 'murlsh/sqlite3_adapter'
|
9
|
-
require 'murlsh/time'
|
10
|
-
require 'murlsh/url_server'
|
11
|
-
require 'murlsh/url'
|
12
|
-
require 'murlsh/uri_ask'
|
13
|
-
require 'murlsh/xhtml_response'
|
14
|
-
|
15
|
-
# requiring builder before active_record blows up
|
16
|
-
require 'murlsh/atom_feed'
|
17
|
-
require 'murlsh/markup'
|
18
|
-
require 'murlsh/url_body'
|
1
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'murlsh', '*.rb')).
|
2
|
+
map { |f| File.join('murlsh', File.basename(f, '.rb')) }.
|
3
|
+
sort.
|
4
|
+
each { |m| require m }
|
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.7.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-04-10}
|
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}
|
@@ -32,24 +32,30 @@ Gem::Specification.new do |s|
|
|
32
32
|
"lib/murlsh/auth.rb",
|
33
33
|
"lib/murlsh/dispatch.rb",
|
34
34
|
"lib/murlsh/doc.rb",
|
35
|
+
"lib/murlsh/etag_add_encoding.rb",
|
35
36
|
"lib/murlsh/failproof.rb",
|
37
|
+
"lib/murlsh/flickr_server.rb",
|
36
38
|
"lib/murlsh/markup.rb",
|
37
39
|
"lib/murlsh/openlock.rb",
|
38
40
|
"lib/murlsh/plugin.rb",
|
39
41
|
"lib/murlsh/sqlite3_adapter.rb",
|
40
|
-
"lib/murlsh/
|
42
|
+
"lib/murlsh/time_ago.rb",
|
41
43
|
"lib/murlsh/uri.rb",
|
42
44
|
"lib/murlsh/uri_ask.rb",
|
43
45
|
"lib/murlsh/url.rb",
|
44
46
|
"lib/murlsh/url_body.rb",
|
45
47
|
"lib/murlsh/url_server.rb",
|
46
48
|
"lib/murlsh/xhtml_response.rb",
|
49
|
+
"lib/murlsh/yaml_ordered_hash.rb",
|
47
50
|
"murlsh.gemspec",
|
48
51
|
"plugins/add_post_50_update_feed.rb",
|
52
|
+
"plugins/add_post_50_update_rss.rb",
|
49
53
|
"plugins/add_post_60_notify_hubs.rb",
|
50
54
|
"plugins/add_pre_50_lookup_content_type_title.rb",
|
51
55
|
"plugins/hostrec_50_redundant.rb",
|
52
56
|
"plugins/hostrec_60_skip.rb",
|
57
|
+
"plugins/time_50_ago.rb",
|
58
|
+
"plugins/via_50_domain.rb",
|
53
59
|
"public/css/jquery.jgrowl.css",
|
54
60
|
"public/css/screen.css",
|
55
61
|
"public/js/jquery-1.4.2.min.js",
|
@@ -59,10 +65,14 @@ Gem::Specification.new do |s|
|
|
59
65
|
"public/swf/player_mp3_mini.swf",
|
60
66
|
"spec/atom_feed_spec.rb",
|
61
67
|
"spec/auth_spec.rb",
|
68
|
+
"spec/dispatch_spec.rb",
|
69
|
+
"spec/doc_spec.rb",
|
62
70
|
"spec/markup_spec.rb",
|
63
71
|
"spec/uri_ask_spec.rb",
|
64
72
|
"spec/uri_spec.rb",
|
65
|
-
"spec/
|
73
|
+
"spec/url_spec.rb",
|
74
|
+
"spec/xhtml_response_spec.rb",
|
75
|
+
"spec/yaml_ordered_hash_spec.rb"
|
66
76
|
]
|
67
77
|
s.homepage = %q{http://github.com/mmb/murlsh}
|
68
78
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -73,9 +83,13 @@ Gem::Specification.new do |s|
|
|
73
83
|
"spec/xhtml_response_spec.rb",
|
74
84
|
"spec/atom_feed_spec.rb",
|
75
85
|
"spec/auth_spec.rb",
|
86
|
+
"spec/yaml_ordered_hash_spec.rb",
|
76
87
|
"spec/uri_ask_spec.rb",
|
88
|
+
"spec/dispatch_spec.rb",
|
77
89
|
"spec/markup_spec.rb",
|
78
|
-
"spec/
|
90
|
+
"spec/url_spec.rb",
|
91
|
+
"spec/uri_spec.rb",
|
92
|
+
"spec/doc_spec.rb"
|
79
93
|
]
|
80
94
|
|
81
95
|
if s.respond_to? :specification_version then
|
@@ -88,6 +102,7 @@ Gem::Specification.new do |s|
|
|
88
102
|
s.add_runtime_dependency(%q<builder>, [">= 2.1.2"])
|
89
103
|
s.add_runtime_dependency(%q<hpricot>, [">= 0.8.1"])
|
90
104
|
s.add_runtime_dependency(%q<htmlentities>, [">= 4.2.0"])
|
105
|
+
s.add_runtime_dependency(%q<json>, [">= 1.2.3"])
|
91
106
|
s.add_runtime_dependency(%q<rack>, [">= 1.0.0"])
|
92
107
|
s.add_runtime_dependency(%q<sqlite3-ruby>, [">= 1.2.1"])
|
93
108
|
else
|
@@ -96,6 +111,7 @@ Gem::Specification.new do |s|
|
|
96
111
|
s.add_dependency(%q<builder>, [">= 2.1.2"])
|
97
112
|
s.add_dependency(%q<hpricot>, [">= 0.8.1"])
|
98
113
|
s.add_dependency(%q<htmlentities>, [">= 4.2.0"])
|
114
|
+
s.add_dependency(%q<json>, [">= 1.2.3"])
|
99
115
|
s.add_dependency(%q<rack>, [">= 1.0.0"])
|
100
116
|
s.add_dependency(%q<sqlite3-ruby>, [">= 1.2.1"])
|
101
117
|
end
|
@@ -105,6 +121,7 @@ Gem::Specification.new do |s|
|
|
105
121
|
s.add_dependency(%q<builder>, [">= 2.1.2"])
|
106
122
|
s.add_dependency(%q<hpricot>, [">= 0.8.1"])
|
107
123
|
s.add_dependency(%q<htmlentities>, [">= 4.2.0"])
|
124
|
+
s.add_dependency(%q<json>, [">= 1.2.3"])
|
108
125
|
s.add_dependency(%q<rack>, [">= 1.0.0"])
|
109
126
|
s.add_dependency(%q<sqlite3-ruby>, [">= 1.2.1"])
|
110
127
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
%w{
|
2
|
+
murlsh
|
3
|
+
}.each { |m| require m }
|
2
4
|
|
3
5
|
module Murlsh
|
4
6
|
|
@@ -14,7 +16,7 @@ module Murlsh
|
|
14
16
|
feed = Murlsh::AtomFeed.new(config.fetch('root_url'),
|
15
17
|
:filename => config.fetch('feed_file'),
|
16
18
|
:title => config.fetch('page_title', ''),
|
17
|
-
:hubs => config.fetch('pubsubhubbub_hubs', []).
|
19
|
+
:hubs => config.fetch('pubsubhubbub_hubs', []).map { |x| x['subscribe_url'] } )
|
18
20
|
|
19
21
|
feed.write(latest, config.fetch('feed_file'))
|
20
22
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
%w{
|
2
|
+
rss/maker
|
3
|
+
|
4
|
+
murlsh
|
5
|
+
}.each { |m| require m }
|
6
|
+
|
7
|
+
module Murlsh
|
8
|
+
|
9
|
+
# Regenerate RSS feed after a new url has been added.
|
10
|
+
class AddPost50UpdateRss < Plugin
|
11
|
+
|
12
|
+
Hook = 'add_post'
|
13
|
+
|
14
|
+
def self.run(config)
|
15
|
+
output_file = 'rss.xml'
|
16
|
+
|
17
|
+
feed = RSS::Maker.make('2.0') do |f|
|
18
|
+
f.channel.title = f.channel.description = config.fetch('page_title', '')
|
19
|
+
f.channel.link = URI.join(config.fetch('root_url'), output_file)
|
20
|
+
f.items.do_sort = true
|
21
|
+
|
22
|
+
Murlsh::Url.all(:order => 'id DESC',
|
23
|
+
:limit => config.fetch('num_posts_feed', 25)).each do |mu|
|
24
|
+
i = f.items.new_item
|
25
|
+
i.title = mu.title_stripped
|
26
|
+
i.link = mu.url
|
27
|
+
i.date = mu.time
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
Murlsh::openlock(output_file, 'w') { |f| f.write(feed) }
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
%w{
|
2
|
+
murlsh
|
3
|
+
}.each { |m| require m }
|
2
4
|
|
3
5
|
module Murlsh
|
4
6
|
|
@@ -11,7 +13,6 @@ module Murlsh
|
|
11
13
|
hubs = config.fetch('pubsubhubbub_hubs', [])
|
12
14
|
|
13
15
|
unless hubs.empty?
|
14
|
-
require 'rubygems'
|
15
16
|
require 'eventmachine'
|
16
17
|
require 'pubsubhubbub'
|
17
18
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
%w{
|
2
|
+
murlsh
|
3
|
+
}.each { |m| require m }
|
4
|
+
|
5
|
+
module Murlsh
|
6
|
+
|
7
|
+
# show the time as the fuzzy amount of time that has elapsed since then
|
8
|
+
class Time50Ago < Plugin
|
9
|
+
|
10
|
+
Hook = 'time'
|
11
|
+
|
12
|
+
def self.run(time); time.extend(Murlsh::TimeAgo).ago if time; end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
%w{
|
2
|
+
murlsh
|
3
|
+
}.each { |m| require m }
|
4
|
+
|
5
|
+
module Murlsh
|
6
|
+
|
7
|
+
# Convert a via url to its display text.
|
8
|
+
#
|
9
|
+
# For most urls the domain is displayed, but for some return custom text.
|
10
|
+
class Via50Domain < Plugin
|
11
|
+
|
12
|
+
Hook = 'via'
|
13
|
+
|
14
|
+
def self.run(via)
|
15
|
+
search = via.to_s.gsub(%r{^http://}, '')
|
16
|
+
|
17
|
+
case
|
18
|
+
when m = search.match(%r{^news\.ycombinator\.com}i)
|
19
|
+
'hacker news'
|
20
|
+
when m = search.match(%r{^www\.reddit\.com/r/([a-z\d]+?)/}i)
|
21
|
+
"#{m[1]}.reddit"
|
22
|
+
when m = search.match(%r{^delicious\.com/(\w+)}i)
|
23
|
+
"delicious/#{m[1]}"
|
24
|
+
when m = search.match(%r{^twitter\.com/(\w+)/}i)
|
25
|
+
"twitter/#{m[1]}"
|
26
|
+
when m = search.match(%r{^([a-z\d][a-z\d-]{0,61}[a-z\d])\.tumblr\.com/}i)
|
27
|
+
"#{m[1]}.tumblr"
|
28
|
+
else
|
29
|
+
via.domain || via
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/public/css/screen.css
CHANGED
@@ -92,6 +92,8 @@ a.feed {
|
|
92
92
|
font-weight : bold;
|
93
93
|
font-size : 0.75em;
|
94
94
|
padding : 2px 4px 2px 4px;
|
95
|
+
-moz-border-radius : 5px;
|
96
|
+
-webkit-border-radius : 5px;
|
95
97
|
}
|
96
98
|
|
97
99
|
span.date {
|
@@ -109,15 +111,11 @@ div.jGrowl div.jGrowl-closer {
|
|
109
111
|
/* iphone */
|
110
112
|
@media screen and (max-device-width : 480px) {
|
111
113
|
|
112
|
-
a.feed {
|
113
|
-
display : none;
|
114
|
-
}
|
115
|
-
|
116
114
|
body {
|
117
115
|
margin : 0;
|
118
116
|
padding : 0;
|
119
117
|
font-size : 1.25em;
|
120
|
-
line-height :
|
118
|
+
line-height : normal;
|
121
119
|
}
|
122
120
|
|
123
121
|
#urls {
|
@@ -128,10 +126,11 @@ div.jGrowl div.jGrowl-closer {
|
|
128
126
|
|
129
127
|
#urls li {
|
130
128
|
overflow : hidden;
|
129
|
+
border-bottom : 1px solid #ccc;
|
131
130
|
}
|
132
131
|
|
133
132
|
input#q {
|
134
|
-
width :
|
133
|
+
width : 110px;
|
135
134
|
}
|
136
135
|
|
137
136
|
input#url, input#via {
|