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.
Files changed (45) hide show
  1. data/.gitignore +3 -0
  2. data/README.textile +25 -2
  3. data/Rakefile +37 -5
  4. data/VERSION +1 -1
  5. data/bin/murlsh +3 -3
  6. data/config.ru +10 -4
  7. data/config.yaml +14 -10
  8. data/lib/murlsh/atom_feed.rb +5 -4
  9. data/lib/murlsh/auth.rb +6 -7
  10. data/lib/murlsh/dispatch.rb +25 -23
  11. data/lib/murlsh/doc.rb +14 -6
  12. data/lib/murlsh/etag_add_encoding.rb +27 -0
  13. data/lib/murlsh/flickr_server.rb +54 -0
  14. data/lib/murlsh/markup.rb +18 -1
  15. data/lib/murlsh/plugin.rb +2 -0
  16. data/lib/murlsh/sqlite3_adapter.rb +3 -1
  17. data/lib/murlsh/time_ago.rb +27 -0
  18. data/lib/murlsh/uri.rb +3 -1
  19. data/lib/murlsh/uri_ask.rb +13 -10
  20. data/lib/murlsh/url.rb +11 -4
  21. data/lib/murlsh/url_body.rb +21 -31
  22. data/lib/murlsh/url_server.rb +1 -2
  23. data/lib/murlsh/yaml_ordered_hash.rb +22 -0
  24. data/lib/murlsh.rb +4 -18
  25. data/murlsh.gemspec +22 -5
  26. data/plugins/add_post_50_update_feed.rb +4 -2
  27. data/plugins/add_post_50_update_rss.rb +37 -0
  28. data/plugins/add_post_60_notify_hubs.rb +3 -2
  29. data/plugins/add_pre_50_lookup_content_type_title.rb +3 -1
  30. data/plugins/time_50_ago.rb +16 -0
  31. data/plugins/via_50_domain.rb +36 -0
  32. data/public/css/screen.css +5 -6
  33. data/public/js/js.js +142 -94
  34. data/spec/atom_feed_spec.rb +21 -20
  35. data/spec/auth_spec.rb +8 -6
  36. data/spec/dispatch_spec.rb +26 -0
  37. data/spec/doc_spec.rb +27 -0
  38. data/spec/markup_spec.rb +3 -1
  39. data/spec/uri_ask_spec.rb +5 -3
  40. data/spec/uri_spec.rb +3 -1
  41. data/spec/url_spec.rb +52 -0
  42. data/spec/xhtml_response_spec.rb +3 -1
  43. data/spec/yaml_ordered_hash_spec.rb +28 -0
  44. metadata +37 -9
  45. data/lib/murlsh/time.rb +0 -20
@@ -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.collect { |x| "MATCH(#{x}, ?)" }.join(' OR ')].push(
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 mu.name
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(via.domain || via, :href => via)
67
+ text!(' via '); a(display_via, :href => via)
65
68
  }
66
69
  end
67
- span(", #{mu.time.fuzzy}", :class => 'date') if
68
- @config.fetch('show_dates', true) and mu.time
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(:description => @config.fetch('description', ''),
89
- :viewport =>
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
- input(:type => 'text', :id => 'q', :name => 'q', :size => 32,
119
- :value => @q)
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 { add_form_input('Add URL:', 'url', 32) }
130
- self.p { add_form_input('Via:', 'via', 32) }
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
- add_form_input('Password:', 'auth', 16, 'password')
133
- input(:type => 'button', :id => 'submit', :value => 'Add')
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
@@ -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
- require 'murlsh/doc'
2
- require 'murlsh/uri'
3
- require 'murlsh/auth'
4
- require 'murlsh/dispatch'
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.6.1"
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-03-10}
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/time.rb",
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/xhtml_response_spec.rb"
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/uri_spec.rb"
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
- require 'murlsh'
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', []).collect { |x| x['subscribe_url'] } )
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
- require 'murlsh'
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
 
@@ -1,4 +1,6 @@
1
- require 'murlsh'
1
+ %w{
2
+ murlsh
3
+ }.each { |m| require m }
2
4
 
3
5
  module Murlsh
4
6
 
@@ -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
@@ -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 : 1.875em;
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 : 130px;
133
+ width : 110px;
135
134
  }
136
135
 
137
136
  input#url, input#via {