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 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