murlsh 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/.htaccess CHANGED
@@ -8,4 +8,5 @@ AddOutputFilterByType DEFLATE text/html
8
8
 
9
9
  <FilesMatch "\.gen\.(css|js)$">
10
10
  Header add Expires "Wed, 22 Jun 2019 20:07:00 GMT"
11
+ FileETag None
11
12
  </FilesMatch>
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
- </code>
30
- </pre>
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
- }.each_slice(2) { |g,v| gemspec.add_dependency(g, ">= #{v}") }
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.8.1
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) }, '.', :verbose => true)
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
- use Rack::Cache,
15
- :verbose => true,
16
- :metastore => 'file:tmp/cache/rack/meta',
17
- :entitystore => 'file:tmp/cache/rack/body'
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
@@ -1,5 +1,7 @@
1
1
  ---
2
2
  auth_file: murlsh_users
3
+ cache_entitystore: file:tmp/cache/rack/body
4
+ cache_metastore: file:tmp/cache/rack/meta
3
5
  css_files:
4
6
  - css/jquery.jgrowl.css
5
7
  - css/screen.css
data/lib/murlsh/doc.rb CHANGED
@@ -1,7 +1,3 @@
1
- %w{
2
- hpricot
3
- }.each { |m| require m }
4
-
5
1
  module Murlsh
6
2
 
7
3
  # Hpricot:Doc mixin.
@@ -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
- json = /.+?\((.+)\)/.match(json_wrapped)[1]
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::Hook == name }.
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; attr_reader :registered end
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
- json = /.+?\((.+)\)/.match(json_wrapped)[1]
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)}\""
@@ -0,0 +1,15 @@
1
+ %w{
2
+ json
3
+ }.each { |m| require m }
4
+
5
+ module Murlsh
6
+
7
+ module_function
8
+
9
+ # Unwrap jsonp to standard json and parse it.
10
+ def unwrap_jsonp(jsonp)
11
+ json = /.+?\((.+)\)/m.match(jsonp)[1]
12
+ JSON.parse(json)
13
+ end
14
+
15
+ end
@@ -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 Hpricot doc at this url.
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 = Hpricot(f).extend(Murlsh::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.1"
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-04-30}
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.6}
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::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
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
- Hook = 'add_post'
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
- feed = Murlsh::AtomFeed.new(config.fetch('root_url'),
17
- :filename => config.fetch('feed_file'),
18
- :title => config.fetch('page_title', ''),
19
- :hubs => config.fetch('pubsubhubbub_hubs', []).map { |x| x['subscribe_url'] } )
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
@@ -9,7 +9,7 @@ module Murlsh
9
9
  # Regenerate RSS feed after a new url has been added.
10
10
  class AddPost50UpdateRss < Plugin
11
11
 
12
- Hook = 'add_post'
12
+ @hook = 'add_post'
13
13
 
14
14
  def self.run(config)
15
15
  output_file = 'rss.xml'
@@ -7,7 +7,7 @@ module Murlsh
7
7
  # notify PubSubHubbub hubs that feed has been updated
8
8
  class AddPost60NotifyHubs < Plugin
9
9
 
10
- Hook = 'add_post'
10
+ @hook = 'add_post'
11
11
 
12
12
  def self.run(config)
13
13
  hubs = config.fetch('pubsubhubbub_hubs', [])
@@ -7,7 +7,7 @@ module Murlsh
7
7
  # try to fetch the content type and title of a url
8
8
  class AddPre50LookupContentTypeTitle < Plugin
9
9
 
10
- Hook = 'add_pre'
10
+ @hook = 'add_pre'
11
11
 
12
12
  def self.run(url, config)
13
13
  ask = URI(url.url).extend(Murlsh::UriAsk)
@@ -8,7 +8,7 @@ module Murlsh
8
8
  # to title.
9
9
  class AddPre60GithubTitle < Plugin
10
10
 
11
- Hook = 'add_pre'
11
+ @hook = 'add_pre'
12
12
 
13
13
  def self.run(url, config)
14
14
  if url.url[%r{http://github.com/\w+/\w+}]
@@ -3,7 +3,7 @@ module Murlsh
3
3
  # skip showing host record if domain is contained in title
4
4
  class Hostrec50Redundant < Plugin
5
5
 
6
- Hook = 'hostrec'
6
+ @hook = 'hostrec'
7
7
 
8
8
  def self.run(domain, url, title)
9
9
  domain unless (title and domain and title.downcase.index(domain))
@@ -1,15 +1,15 @@
1
1
  module Murlsh
2
2
 
3
- # skip showing host record for some domains
3
+ # Skip showing host record for some domains.
4
4
  class Hostrec60Skip < Plugin
5
5
 
6
- Hook = 'hostrec'
6
+ @hook = 'hostrec'
7
7
 
8
8
  def self.run(domain, url, title)
9
- domain unless Skips.include?(domain)
9
+ domain unless skips.include?(domain)
10
10
  end
11
11
 
12
- Skips = %w{
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
@@ -7,7 +7,7 @@ module Murlsh
7
7
  # show the time as the fuzzy amount of time that has elapsed since then
8
8
  class Time50Ago < Plugin
9
9
 
10
- Hook = 'time'
10
+ @hook = 'time'
11
11
 
12
12
  def self.run(time); time.extend(Murlsh::TimeAgo).ago if time; end
13
13
 
@@ -9,7 +9,7 @@ module Murlsh
9
9
  # For most urls the domain is displayed, but for some return custom text.
10
10
  class Via50Domain < Plugin
11
11
 
12
- Hook = 'via'
12
+ @hook = 'via'
13
13
 
14
14
  def self.run(via)
15
15
  search = via.to_s.gsub(%r{^http://}, '')
@@ -54,6 +54,11 @@ img.thumb, li object {
54
54
  -webkit-border-radius : 5px;
55
55
  }
56
56
 
57
+ img.thumb.twitter {
58
+ height : 48px;
59
+ width : 48px;
60
+ }
61
+
57
62
  span.host {
58
63
  color : #808080;
59
64
  font-family : monospace;
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 = 'png';
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
- /^http:\/\/twitter\.com\/\w+\/status(?:es)?\/(\d+)$/i,
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 SocketError when getting the content type of an invalid URI when given failproof option false' do
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(SocketError)
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 SocketError when trying to get the title of an invalid URI when given failproof option false' do
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(SocketError)
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
8
- - 1
9
- version: 0.8.1
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-04-30 00:00:00 -04:00
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: sqlite3-ruby
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: *id009
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.6
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
@@ -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
@@ -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