murlsh 1.8.0 → 1.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/ChangeLog CHANGED
@@ -1,3 +1,20 @@
1
+ 1.9.0
2
+ 2011-09-25
3
+
4
+ Do not strip trailing slashes from urls during normalization.
5
+
6
+ Add enclosures to JSON.
7
+
8
+ Support multiple enclosures per url that can be set by plugins.
9
+
10
+ Plugins for adding enclosures for YouTube and Vimeo urls.
11
+
12
+ Support builder version 3.
13
+
14
+ Update user agent sent when asking about urls to more recent browser.
15
+
16
+ Use "required" instead of "optional" attribute for form inputs.
17
+
1
18
  1.8.0
2
19
  2011-06-22
3
20
 
@@ -0,0 +1,32 @@
1
+ require 'murlsh'
2
+
3
+ class CreateEnclosures < ActiveRecord::Migration
4
+
5
+ def self.up
6
+ create_table :enclosures do |t|
7
+ t.integer :content_length
8
+ t.string :content_type
9
+ t.string :title
10
+ t.string :enclosure_url
11
+
12
+ t.references :url
13
+ end
14
+
15
+ add_index :enclosures, :url_id
16
+
17
+ # populate
18
+ require './plugins/add_pre_55_enclosure_self.rb'
19
+ require './plugins/add_pre_55_enclosure_vimeo.rb'
20
+ require './plugins/add_pre_55_enclosure_youtube.rb'
21
+
22
+ Murlsh::Url.find(:all).each do |u|
23
+ Murlsh::Plugin.hooks('add_pre') { |p| p.run u, {} }
24
+ u.save!
25
+ end
26
+ end
27
+
28
+ def self.down
29
+ drop_table :enclosures
30
+ end
31
+
32
+ end
@@ -29,15 +29,17 @@ module Murlsh
29
29
  :summary => mu.title_stripped
30
30
  }
31
31
 
32
- if EnclosureContentTypes.include?(mu.content_type)
33
- options.merge!(
34
- :enclosure_type => mu.content_type,
35
- :enclosure_href => mu.url,
36
- :enclosure_title => mu.title
37
- )
38
- if mu.content_length
39
- options.merge! :enclosure_length => mu.content_length
40
- end
32
+ options[:enclosures] = []
33
+ mu.enclosures.each do |e|
34
+ new_e = {
35
+ :enclosure_href => e.enclosure_url,
36
+ :enclosure_title => e.title_stripped,
37
+ :enclosure_type => e.content_type
38
+ }
39
+
40
+ new_e[:enclosure_length] = e.content_length if e.content_length
41
+
42
+ options[:enclosures] << new_e
41
43
  end
42
44
 
43
45
  if mu.thumbnail_url
@@ -0,0 +1,14 @@
1
+ require 'active_record'
2
+
3
+ module Murlsh
4
+
5
+ # Enclosure ActiveRecord.
6
+ class Enclosure < ActiveRecord::Base
7
+ belongs_to :url
8
+
9
+ # Title with whitespace compressed and leading and trailing whitespace
10
+ # stripped.
11
+ def title_stripped; title.to_s.strip.gsub(/\s+/, ' '); end
12
+ end
13
+
14
+ end
@@ -3,15 +3,6 @@ module Murlsh
3
3
  # Feed body mixin.
4
4
  module FeedBody
5
5
 
6
- # Content types to add an enclosure for.
7
- EnclosureContentTypes = %w{
8
- application/pdf
9
- audio/mpeg
10
- image/gif
11
- image/jpeg
12
- image/png
13
- }
14
-
15
6
  def initialize(config, req, feed_url, urls)
16
7
  @config, @req, @feed_url, @urls = config, req, feed_url, urls
17
8
  @updated = nil
@@ -33,6 +33,12 @@ module Murlsh
33
33
  h['thumbnail_url']).to_s
34
34
  end
35
35
 
36
+ h['enclosures'] = mu.enclosures.map do |e|
37
+ new_e = e.attributes.reject { |k,v| k == 'url_id' }
38
+ new_e['title'] = e.title_stripped
39
+ new_e
40
+ end
41
+
36
42
  h
37
43
  end
38
44
  @body = urls.to_json
data/lib/murlsh/markup.rb CHANGED
@@ -8,7 +8,7 @@ module Murlsh
8
8
  # Options:
9
9
  # * :prefix - prefix to append to all script urls
10
10
  def javascript(sources, options={})
11
- Array(sources).each do |src|
11
+ ::Kernel::Array(sources).each do |src|
12
12
  script '', :type => 'text/javascript',
13
13
  :src => "#{options[:prefix]}#{src}"
14
14
  end
@@ -50,7 +50,7 @@ module Murlsh
50
50
  # * :media - optional media attribute
51
51
  # * :prefix - prepended to all CSS urls
52
52
  def css(hrefs, options={})
53
- Array(hrefs).each do |href|
53
+ ::Kernel::Array(hrefs).each do |href|
54
54
  attrs = {
55
55
  :href => "#{options[:prefix]}#{href}",
56
56
  :rel => 'stylesheet',
@@ -69,7 +69,7 @@ module Murlsh
69
69
  def form_input(options)
70
70
  if options[:id]
71
71
  if options[:label]
72
- label_class = options[:optional] ? 'optional' : 'required'
72
+ label_class = options[:required] ? 'required' : 'optional'
73
73
  label options[:label], :for => options[:id], :class => label_class
74
74
  end
75
75
  options[:name] ||= options[:id]
@@ -29,11 +29,12 @@ module Murlsh
29
29
  i.link = mu.url
30
30
  i.date = mu.time
31
31
 
32
- if EnclosureContentTypes.include? mu.content_type
33
- i.enclosure.url = mu.url
34
- i.enclosure.type = mu.content_type
35
- i.enclosure.length = mu.content_length
32
+ mu.enclosures.first(1).each do |e|
33
+ i.enclosure.url = e.enclosure_url
34
+ i.enclosure.type = e.content_type
35
+ i.enclosure.length = e.content_length
36
36
  end
37
+
37
38
  end
38
39
  end
39
40
 
@@ -93,7 +93,7 @@ module Murlsh
93
93
  def default_headers
94
94
  result = {
95
95
  'User-Agent' =>
96
- 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624',
96
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.126 Safari/535.1',
97
97
  }
98
98
  if host.to_s[/^www\.nytimes\.com/]
99
99
  result['Referer'] = 'http://news.google.com/'
data/lib/murlsh/url.rb CHANGED
@@ -6,6 +6,7 @@ module Murlsh
6
6
 
7
7
  # URL ActiveRecord.
8
8
  class Url < ActiveRecord::Base
9
+ has_many :enclosures
9
10
  validates_format_of :url, :with => URI.regexp
10
11
 
11
12
  # Get the title of this url.
@@ -21,7 +22,7 @@ module Murlsh
21
22
 
22
23
  # Title with whitespace compressed and leading and trailing whitespace
23
24
  # stripped.
24
- def title_stripped; title.strip.gsub(/\s+/, ' '); end
25
+ def title_stripped; title.to_s.strip.gsub(/\s+/, ' '); end
25
26
 
26
27
  # Return true if this url has the same author as another url.
27
28
  def same_author?(other)
@@ -5,7 +5,7 @@ module Murlsh
5
5
 
6
6
  # Url list page builder.
7
7
  class UrlBody < Builder::XmlMarkup
8
- include Murlsh::Markup
8
+ include ::Murlsh::Markup
9
9
 
10
10
  def initialize(config, req, result_set, content_type='text/html')
11
11
  @config, @req, @result_set, @content_type = config, req, result_set,
@@ -20,7 +20,7 @@ module Murlsh
20
20
  if page.to_i >= 1
21
21
  query = @req.params.dup
22
22
  query['p'] = page
23
- Murlsh.build_query(query)
23
+ ::Murlsh.build_query(query)
24
24
  end
25
25
  end
26
26
 
@@ -50,13 +50,13 @@ module Murlsh
50
50
  last = nil
51
51
 
52
52
  @result_set.results.each do |mu|
53
- Murlsh::Plugin.hooks('url_display_pre') do |p|
53
+ ::Murlsh::Plugin.hooks('url_display_pre') do |p|
54
54
  p.run mu, @req, @config
55
55
  end
56
56
 
57
57
  li(:id => "liu#{mu.id}") {
58
58
  unless mu.same_author?(last)
59
- avatar_url = Murlsh::Plugin.hooks('avatar').inject(
59
+ avatar_url = ::Murlsh::Plugin.hooks('avatar').inject(
60
60
  nil) do |url_so_far,plugin|
61
61
  plugin.run url_so_far, mu, @config
62
62
  end
@@ -74,7 +74,7 @@ module Murlsh
74
74
 
75
75
  a mu.title_stripped, :href => mu.url, :class => 'm'
76
76
 
77
- Murlsh::Plugin.hooks('url_display_add') do |p|
77
+ ::Murlsh::Plugin.hooks('url_display_add') do |p|
78
78
  p.run self, mu, @config
79
79
  end
80
80
 
@@ -154,7 +154,7 @@ module Murlsh
154
154
  order += (@config['quick_search'].keys - order).sort
155
155
  order.each do |k|
156
156
  if v = @config['quick_search'][k]
157
- a "/#{k}", :href => "?q=#{URI.escape(v)}" ; text! ' '
157
+ a "/#{k}", :href => "?q=#{::URI.escape(v)}" ; text! ' '
158
158
  end
159
159
  end
160
160
  }
@@ -188,18 +188,15 @@ module Murlsh
188
188
  def add_form
189
189
  form(:action => 'url', :method => 'post') {
190
190
  fieldset(:id => 'add') {
191
- self.p { form_input :id => 'url', :label => 'Add URL', :size => 32 }
192
191
  self.p {
193
- form_input :id => 'title', :label => 'Title', :size => 32,
194
- :optional => true
195
- }
196
- self.p {
197
- form_input :id => 'via', :label => 'Via', :size => 32,
198
- :optional => true
192
+ form_input :id => 'url', :label => 'Add URL', :size => 32,
193
+ :required => ''
199
194
  }
195
+ self.p { form_input :id => 'title', :label => 'Title', :size => 32 }
196
+ self.p { form_input :id => 'via', :label => 'Via', :size => 32 }
200
197
  self.p {
201
198
  form_input :type => 'password', :id => 'auth', :label => 'Password',
202
- :size => 16
199
+ :size => 16, :required => ''
203
200
  form_input :id => 'submit', :type => 'button', :value => 'Add'
204
201
  }
205
202
  }
@@ -1,3 +1,3 @@
1
1
  module Murlsh
2
- VERSION = '1.8.0'
2
+ VERSION = '1.9.0'
3
3
  end
data/lib/murlsh.rb CHANGED
@@ -11,6 +11,7 @@ require 'murlsh/delicious_parse'
11
11
  require 'murlsh/dispatch'
12
12
  require 'murlsh/doc'
13
13
  require 'murlsh/etag_add_encoding'
14
+ require 'murlsh/enclosure'
14
15
  require 'murlsh/failproof'
15
16
  require 'murlsh/far_future_expires'
16
17
  require 'murlsh/feed_body'
@@ -4,26 +4,49 @@ require 'postrank-uri'
4
4
 
5
5
  require 'murlsh'
6
6
 
7
+ # Patch PostRank::URI.normalize to not strip trailing slashes from the path.
8
+ module PostRank
9
+
10
+ module URI
11
+
12
+ module_function
13
+
14
+ def normalize(uri, opts = {})
15
+ u = parse(uri, opts)
16
+ u.path = u.path.squeeze('/')
17
+ # u.path = u.path.chomp('/') if u.path.size != 1
18
+ u.query = nil if u.query && u.query.empty?
19
+ u.fragment = nil
20
+ u
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
7
27
  module Murlsh
8
28
 
9
- # Canonicalize and clean urls with postrank-uri.
10
- #
11
- # See https://github.com/postrank-labs/postrank-uri
29
+ # Canonicalize and clean urls.
30
+
12
31
  class AddPre35UrlClean < Plugin
13
32
 
14
33
  @hook = 'add_pre'
15
34
 
16
35
  def self.run(url, config)
17
- url.url = PostRank::URI.clean(url.url) if cleanable?(url.url)
18
- url.via = PostRank::URI.clean(url.via) if cleanable?(url.via)
36
+ Murlsh::failproof { url.url = clean(url.url) if cleanable?(url.url) }
37
+ Murlsh::failproof { url.via = clean(url.via) if cleanable?(url.via) }
19
38
  end
20
39
 
21
- # Return true if the url can be cleaned by postrank-uri.
40
+ # Canonicalize and clean a url using PostRank::URI.clean.
22
41
  #
23
- # Postrank::URI.clean only works on https or https urls.
24
- def self.cleanable?(url)
25
- Murlsh::failproof { URI(url).scheme.to_s.match(/^https?$/i) }
26
- end
42
+ # PostRank::URI.normalize is patched to not strip trailing slashes from
43
+ # the path (see above).
44
+ #
45
+ # See https://github.com/postrank-labs/postrank-uri
46
+ def self.clean(url); PostRank::URI.clean(url); end
47
+
48
+ # Return true if the url can be cleaned (is http or https).
49
+ def self.cleanable?(url); URI(url).scheme.to_s.match(/^https?$/i); end
27
50
 
28
51
  end
29
52
 
@@ -0,0 +1,31 @@
1
+ require 'murlsh'
2
+
3
+ module Murlsh
4
+
5
+ # Create enclosures for content types that can directly become enclosures.
6
+ class AddPre55EnclosureSelf < Plugin
7
+
8
+ @hook = 'add_pre'
9
+
10
+ # Content types that can be enclosures.
11
+ ContentTypes = %w{
12
+ application/pdf
13
+ audio/mpeg
14
+ image/gif
15
+ image/jpeg
16
+ image/png
17
+ }
18
+
19
+ def self.run(url, config)
20
+ if ContentTypes.include?(url.content_type)
21
+ url.enclosures.build(
22
+ :content_length => url.content_length,
23
+ :title => url.title,
24
+ :content_type => url.content_type,
25
+ :enclosure_url => url.url)
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,24 @@
1
+ require 'murlsh'
2
+
3
+ module Murlsh
4
+
5
+ # Create video enclosures for Vimeo urls.
6
+ class AddPre55EnclosureVimeo < Plugin
7
+
8
+ @hook = 'add_pre'
9
+
10
+ VimeoRe = %r{^http://(?:www\.)?vimeo\.com/(\d+)$}i
11
+
12
+ def self.run(url, config)
13
+ if match = VimeoRe.match(url.url)
14
+ url.enclosures.build(
15
+ :title => url.title,
16
+ :content_type => 'application/x-shockwave-flash',
17
+ :enclosure_url =>
18
+ "http://vimeo.com/moogaloop.swf?clip_id=#{match[1]}")
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'murlsh'
2
+
3
+ module Murlsh
4
+
5
+ # Create video enclosures for YouTube urls.
6
+ class AddPre55EnclosureYoutube < Plugin
7
+
8
+ @hook = 'add_pre'
9
+
10
+ YoutubeRe =
11
+ %r{^http://(?:(?:www|uk)\.)?youtube\.com/watch\?v=([\w\-]+)(?:&|$)}i
12
+
13
+ def self.run(url, config)
14
+ if match = YoutubeRe.match(url.url)
15
+ url.enclosures.build(
16
+ :title => url.title,
17
+ :content_type => 'application/x-shockwave-flash',
18
+ :enclosure_url => "http://www.youtube.com/v/#{match[1]}.swf")
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: murlsh
3
3
  version: !ruby/object:Gem::Version
4
- hash: 55
4
+ hash: 51
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 8
8
+ - 9
9
9
  - 0
10
- version: 1.8.0
10
+ version: 1.9.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matthew M. Boedicker
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-22 00:00:00 -04:00
18
+ date: 2011-09-25 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -377,6 +377,7 @@ files:
377
377
  - config.yaml
378
378
  - config/README
379
379
  - db/migrate/20110213023123_init.rb
380
+ - db/migrate/20110906003222_create_enclosures.rb
380
381
  - lib/murlsh.rb
381
382
  - lib/murlsh/ask.rb
382
383
  - lib/murlsh/atom_body.rb
@@ -388,6 +389,7 @@ files:
388
389
  - lib/murlsh/delicious_parse.rb
389
390
  - lib/murlsh/dispatch.rb
390
391
  - lib/murlsh/doc.rb
392
+ - lib/murlsh/enclosure.rb
391
393
  - lib/murlsh/etag_add_encoding.rb
392
394
  - lib/murlsh/failproof.rb
393
395
  - lib/murlsh/far_future_expires.rb
@@ -433,6 +435,9 @@ files:
433
435
  - plugins/add_pre_50_lookup_content_type_title.rb
434
436
  - plugins/add_pre_50_media_thumbnail.rb
435
437
  - plugins/add_pre_50_open_graph_image.rb
438
+ - plugins/add_pre_55_enclosure_self.rb
439
+ - plugins/add_pre_55_enclosure_vimeo.rb
440
+ - plugins/add_pre_55_enclosure_youtube.rb
436
441
  - plugins/add_pre_55_open_graph_title.rb
437
442
  - plugins/add_pre_60_github_title.rb
438
443
  - plugins/add_pre_60_imgur.rb