better_opener 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.rdoc +34 -0
- data/Rakefile +1 -0
- data/better_opener.gemspec +32 -0
- data/config.ru +4 -0
- data/lib/better_opener.rb +87 -0
- data/lib/better_opener/delivery_method.rb +13 -0
- data/lib/better_opener/email.html.erb +88 -0
- data/lib/better_opener/railtie.rb +8 -0
- data/lib/better_opener/server.rb +60 -0
- data/lib/better_opener/server/views/atom.haml +17 -0
- data/lib/better_opener/server/views/index.haml +14 -0
- data/lib/better_opener/server/views/show.haml +4 -0
- data/lib/better_opener/sms.html.erb +99 -0
- data/lib/better_opener/sms_gateway_adapter.rb +22 -0
- data/lib/better_opener/version.rb +3 -0
- data/lib/test.ru +8 -0
- metadata +153 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
= Better Opener
|
2
|
+
|
3
|
+
Preview mails and other notifications (sms for instance) in your browser
|
4
|
+
instead of actually sending them out. Inspired and almost similar to the
|
5
|
+
Letter Opener by Ryan Bates Better Opener this gem tries to be *better* by being
|
6
|
+
more universal and displaying desktop notifications (with the chrome plugin).
|
7
|
+
|
8
|
+
== Setup
|
9
|
+
|
10
|
+
Add the gem to your development environment and run the <tt>bundle install</tt> command to install it.
|
11
|
+
|
12
|
+
gem "better_opener", :group => :development
|
13
|
+
|
14
|
+
Set the delivery method in <tt>config/environments/development.rb</tt>
|
15
|
+
|
16
|
+
config.action_mailer.delivery_method = :letter_opener
|
17
|
+
|
18
|
+
Finally install the bundled Sinatra app as a subdirectory of your app by editing your <tt>config.ru</tt>:
|
19
|
+
|
20
|
+
map "/notification" do
|
21
|
+
run BetterOpener::Server
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
== Chrome Plugin
|
27
|
+
|
28
|
+
To take full advantage and get actual notifications, you will want to install
|
29
|
+
the accompanying chrome plugin. Just point it to the notification address you
|
30
|
+
set up above.
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "better_opener/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "better_opener"
|
7
|
+
s.version = BetterOpener::VERSION
|
8
|
+
s.authors = ["Kai Rubarth"]
|
9
|
+
s.email = ["kai@doxter.de"]
|
10
|
+
s.homepage = "http://github.com/learnjin/better_opener"
|
11
|
+
s.summary = %q{A better way of Previewing mail in your browser instead of sending it.}
|
12
|
+
s.description = %q{When mails or messages are sent from your application, Better Opener lets you preview the rendered messages in your browser instead of delivering them.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "better_opener"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_development_dependency "sinatra-contrib"
|
23
|
+
|
24
|
+
s.add_dependency "data_mapper", ">= 1.2"
|
25
|
+
s.add_dependency "dm-sqlite-adapter"
|
26
|
+
s.add_dependency "tilt"
|
27
|
+
s.add_dependency "haml"
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
|
data/config.ru
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require "better_opener/version"
|
2
|
+
|
3
|
+
require 'data_mapper'
|
4
|
+
require 'time'
|
5
|
+
require 'tilt'
|
6
|
+
require 'rack/mime'
|
7
|
+
|
8
|
+
module BetterOpener
|
9
|
+
|
10
|
+
class Notification
|
11
|
+
include DataMapper::Resource
|
12
|
+
property :id, Serial
|
13
|
+
property :subject, String
|
14
|
+
property :body, Text
|
15
|
+
property :created_at, DateTime
|
16
|
+
property :category, String
|
17
|
+
end
|
18
|
+
|
19
|
+
extend self
|
20
|
+
|
21
|
+
def db=(server)
|
22
|
+
@db = server
|
23
|
+
end
|
24
|
+
|
25
|
+
def db
|
26
|
+
return @db if @db
|
27
|
+
self.db = DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/development.db")
|
28
|
+
DataMapper.auto_upgrade!
|
29
|
+
self.db
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_all_notifications
|
33
|
+
db && BetterOpener::Notification.all(:order => [:id.desc])
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_notification(id)
|
37
|
+
db && BetterOpener::Notification.get(id)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def add_notification(category, subject, body)
|
42
|
+
db
|
43
|
+
n = BetterOpener::Notification.new :category => category, :subject => subject, :body => body, :created_at => Time.now
|
44
|
+
n.save
|
45
|
+
end
|
46
|
+
|
47
|
+
def email_template_path
|
48
|
+
File.expand_path('../better_opener/email.html.erb', __FILE__)
|
49
|
+
end
|
50
|
+
|
51
|
+
def email_template
|
52
|
+
Tilt.new(email_template_path)
|
53
|
+
end
|
54
|
+
|
55
|
+
def render_email(name, mail, format = nil)
|
56
|
+
body_part = mail
|
57
|
+
|
58
|
+
if mail.multipart?
|
59
|
+
content_type = Rack::Mime.mime_type(format)
|
60
|
+
body_part = mail.parts.find { |part| part.content_type.match(content_type) } || mail.parts.first
|
61
|
+
end
|
62
|
+
|
63
|
+
email_template.render(Object.new, :name => name, :mail => mail, :body_part => body_part)
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def sms_template_path
|
68
|
+
File.expand_path('../better_opener/sms.html.erb', __FILE__)
|
69
|
+
end
|
70
|
+
|
71
|
+
def sms_template
|
72
|
+
Tilt.new(sms_template_path)
|
73
|
+
end
|
74
|
+
|
75
|
+
def render_sms(name, sms, format = nil)
|
76
|
+
sms_template.render(Object.new, :name => name, :sms => sms)
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
require 'better_opener/delivery_method'
|
83
|
+
require 'better_opener/server'
|
84
|
+
require "better_opener/railtie" if defined? Rails
|
85
|
+
require "better_opener/sms_gateway_adapter" if defined? SmsGateway
|
86
|
+
|
87
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
<head>
|
2
|
+
<meta http-equiv="Content-Type" content="text/html; charset=<%= body_part.charset %>" />
|
3
|
+
</head>
|
4
|
+
<style type="text/css">
|
5
|
+
#message_headers {
|
6
|
+
position: absolute;
|
7
|
+
top: 0px;
|
8
|
+
left: 0;
|
9
|
+
width: 100%;
|
10
|
+
height: 85px;
|
11
|
+
padding: 10px 0 0 0;
|
12
|
+
margin: 0;
|
13
|
+
background: #fff;
|
14
|
+
font-size: 12px;
|
15
|
+
font-family: "Lucida Grande";
|
16
|
+
border-bottom: 1px solid #dedede;
|
17
|
+
overflow: hidden;
|
18
|
+
}
|
19
|
+
|
20
|
+
#message_headers dl {
|
21
|
+
margin: 0;
|
22
|
+
padding: 0;
|
23
|
+
}
|
24
|
+
|
25
|
+
#message_headers dt {
|
26
|
+
width: 60px;
|
27
|
+
padding: 1px;
|
28
|
+
float: left;
|
29
|
+
text-align: right;
|
30
|
+
font-weight: bold;
|
31
|
+
color: #7f7f7f;
|
32
|
+
}
|
33
|
+
|
34
|
+
#message_headers dd {
|
35
|
+
margin-left: 70px;
|
36
|
+
padding: 1px;
|
37
|
+
}
|
38
|
+
|
39
|
+
#message_headers p.alternate {
|
40
|
+
position: absolute;
|
41
|
+
top: 0;
|
42
|
+
right: 15px;
|
43
|
+
}
|
44
|
+
|
45
|
+
#message_headers p.alternate a {
|
46
|
+
color: #09c;
|
47
|
+
}
|
48
|
+
|
49
|
+
pre#message_body {
|
50
|
+
padding: 10px;
|
51
|
+
white-space: pre-wrap;
|
52
|
+
}
|
53
|
+
|
54
|
+
body {
|
55
|
+
margin-top: 96px;
|
56
|
+
}
|
57
|
+
</style>
|
58
|
+
<div id="message_headers">
|
59
|
+
<dl>
|
60
|
+
<dt>From:</dt>
|
61
|
+
<dd><%= mail.from %></dd>
|
62
|
+
|
63
|
+
<dt>Subject:</dt>
|
64
|
+
<dd><strong><%= mail.subject %></strong></dd>
|
65
|
+
|
66
|
+
<dt>Date:</dt>
|
67
|
+
<dd><%= Time.now.strftime("%b %e, %Y %I:%M:%S %p %Z") %></dd>
|
68
|
+
|
69
|
+
<dt>To:</dt>
|
70
|
+
<dd><%= mail.to %></dd>
|
71
|
+
</dl>
|
72
|
+
|
73
|
+
<% if mail.multipart? %>
|
74
|
+
<p class="alternate">
|
75
|
+
<% if body_part.content_type && body_part.content_type.match(/text\/html/) %>
|
76
|
+
<a href="<%= name %>.txt">View plain text version</a>
|
77
|
+
<% else %>
|
78
|
+
<a href="<%= name %>.html">View HTML version</a>
|
79
|
+
<% end %>
|
80
|
+
</p>
|
81
|
+
<% end %>
|
82
|
+
</div>
|
83
|
+
|
84
|
+
<% if body_part.content_type && body_part.content_type.match(/text\/html/) %>
|
85
|
+
<%= body_part.body %>
|
86
|
+
<% else %>
|
87
|
+
<pre id="message_body"><%= body_part.body %></pre>
|
88
|
+
<% end %>
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubygems' if RUBY_VERSION < '1.9'
|
2
|
+
require 'sinatra'
|
3
|
+
#require 'sinatra/reloader' if development?
|
4
|
+
require 'haml'
|
5
|
+
require 'data_mapper'
|
6
|
+
require 'better_opener'
|
7
|
+
|
8
|
+
module BetterOpener
|
9
|
+
|
10
|
+
class Server < Sinatra::Base
|
11
|
+
#configure :development do
|
12
|
+
# register Sinatra::Reloader
|
13
|
+
#nd
|
14
|
+
|
15
|
+
helpers do
|
16
|
+
include Rack::Utils
|
17
|
+
alias_method :h, :escape_html
|
18
|
+
|
19
|
+
def url_path(*path_parts)
|
20
|
+
path = [ path_prefix, path_parts ].join("/").squeeze('/')
|
21
|
+
request.scheme + "://" + request.host_with_port + path
|
22
|
+
end
|
23
|
+
alias_method :u, :url_path
|
24
|
+
|
25
|
+
def path_prefix
|
26
|
+
request.script_name
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
dir = File.dirname(File.expand_path(__FILE__))
|
32
|
+
|
33
|
+
set :views, "#{dir}/server/views"
|
34
|
+
set :public, "#{dir}/server/public"
|
35
|
+
set :static, true
|
36
|
+
|
37
|
+
get "/" do
|
38
|
+
@messages = BetterOpener.get_all_notifications
|
39
|
+
haml :index
|
40
|
+
end
|
41
|
+
|
42
|
+
get "/purge" do
|
43
|
+
BetterOpener::Notification.all.destroy
|
44
|
+
redirect u('/')
|
45
|
+
end
|
46
|
+
|
47
|
+
get "/:id" do
|
48
|
+
@message = BetterOpener.get_notification(params[:id])
|
49
|
+
@message.body
|
50
|
+
end
|
51
|
+
|
52
|
+
get "/feed/atom", :provides => [:atom] do
|
53
|
+
@messages = BetterOpener.get_all_notifications
|
54
|
+
content_type 'application/rss+xml'
|
55
|
+
haml(:atom, :format => :xhtml, :escape_html => true, :layout => false)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
!!! XML
|
2
|
+
%feed{:version=> "0.3", :xmlns=> "http://purl.org/atom/ns#"}
|
3
|
+
%title Notification Outbox
|
4
|
+
%tagline Messages in your Outbox
|
5
|
+
%fullcount= @messages.size
|
6
|
+
%link{:rel=>"alternate", :href => u("/"), :type => "text/html"}
|
7
|
+
%modified= @messages.size > 0 ? @messages.first.created_at : Time.now
|
8
|
+
- for message in @messages
|
9
|
+
%entry
|
10
|
+
%title= message.subject
|
11
|
+
%summary= "#{message.subject} ..."
|
12
|
+
%link{:rel => "alternate", :href => u("/#{message.id}")}
|
13
|
+
%modified= message.created_at
|
14
|
+
%issued= message.created_at
|
15
|
+
%category= message.category
|
16
|
+
%id= message.id
|
17
|
+
|
@@ -0,0 +1,99 @@
|
|
1
|
+
<head>
|
2
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
3
|
+
</head>
|
4
|
+
<style type="text/css">
|
5
|
+
#message_headers {
|
6
|
+
position: absolute;
|
7
|
+
top: 0px;
|
8
|
+
left: 0;
|
9
|
+
width: 100%;
|
10
|
+
height: 65px;
|
11
|
+
padding: 10px 0 0 0;
|
12
|
+
margin: 0;
|
13
|
+
background: #fff;
|
14
|
+
font-size: 12px;
|
15
|
+
font-family: "Lucida Grande";
|
16
|
+
/*border-bottom: 1px solid #dedede;*/
|
17
|
+
overflow: hidden;
|
18
|
+
}
|
19
|
+
|
20
|
+
#message_headers dl {
|
21
|
+
margin: 0;
|
22
|
+
padding: 0;
|
23
|
+
}
|
24
|
+
|
25
|
+
#message_headers dt {
|
26
|
+
width: 60px;
|
27
|
+
padding: 1px;
|
28
|
+
float: left;
|
29
|
+
text-align: right;
|
30
|
+
font-weight: bold;
|
31
|
+
color: #7f7f7f;
|
32
|
+
}
|
33
|
+
|
34
|
+
#message_headers dd {
|
35
|
+
margin-left: 70px;
|
36
|
+
padding: 1px;
|
37
|
+
}
|
38
|
+
|
39
|
+
#message_headers p.alternate {
|
40
|
+
position: absolute;
|
41
|
+
top: 0;
|
42
|
+
right: 15px;
|
43
|
+
}
|
44
|
+
|
45
|
+
#message_headers p.alternate a {
|
46
|
+
color: #09c;
|
47
|
+
}
|
48
|
+
|
49
|
+
pre#message_body {
|
50
|
+
padding: 10px;
|
51
|
+
white-space: pre-wrap;
|
52
|
+
}
|
53
|
+
|
54
|
+
body {
|
55
|
+
margin-top: 96px;
|
56
|
+
}
|
57
|
+
|
58
|
+
#sms_body{
|
59
|
+
}
|
60
|
+
|
61
|
+
div.outcome {
|
62
|
+
background-color: #A3E6A5;
|
63
|
+
border-top-left-radius: 0;
|
64
|
+
-moz-border-radius-topleft: 0;
|
65
|
+
margin-left: 2em;
|
66
|
+
}
|
67
|
+
|
68
|
+
.message {
|
69
|
+
border: 1px solid #ccc;
|
70
|
+
border-radius: 10px;
|
71
|
+
-moz-border-radius: 10px;
|
72
|
+
padding: .5em;
|
73
|
+
margin-bottom: 1em;
|
74
|
+
width: 500px;
|
75
|
+
}
|
76
|
+
|
77
|
+
</style>
|
78
|
+
<div id="message_headers">
|
79
|
+
<dl>
|
80
|
+
<dt>From:</dt>
|
81
|
+
<dd><%= sms.from %></dd>
|
82
|
+
|
83
|
+
<dt>To:</dt>
|
84
|
+
<dd><%= sms.to %></dd>
|
85
|
+
|
86
|
+
<dt>Date:</dt>
|
87
|
+
<dd><%= Time.now.strftime("%b %e, %Y %I:%M:%S %p %Z") %></dd>
|
88
|
+
|
89
|
+
</dl>
|
90
|
+
|
91
|
+
</div>
|
92
|
+
|
93
|
+
<div id="sms_body">
|
94
|
+
<div class="outcome message">
|
95
|
+
<%= sms.text %>
|
96
|
+
</div>
|
97
|
+
</div>
|
98
|
+
|
99
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'sms_gateway'
|
2
|
+
|
3
|
+
module SmsGateway
|
4
|
+
|
5
|
+
module Adapters
|
6
|
+
class BetterOpener
|
7
|
+
|
8
|
+
def initialize(config={})
|
9
|
+
@config = {:from => SmsGateway::Base.from }
|
10
|
+
@config.merge!(config)
|
11
|
+
end
|
12
|
+
|
13
|
+
def send_sms(sms)
|
14
|
+
options = @config.merge({:to => sms.to, :message => sms.text })
|
15
|
+
::BetterOpener.add_notification("sms", sms.from, ::BetterOpener.render_sms('sms', sms) )
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
data/lib/test.ru
ADDED
metadata
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: better_opener
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Kai Rubarth
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-03-02 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: sinatra-contrib
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: data_mapper
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 11
|
43
|
+
segments:
|
44
|
+
- 1
|
45
|
+
- 2
|
46
|
+
version: "1.2"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: dm-sqlite-adapter
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :runtime
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: tilt
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :runtime
|
76
|
+
version_requirements: *id004
|
77
|
+
- !ruby/object:Gem::Dependency
|
78
|
+
name: haml
|
79
|
+
prerelease: false
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
type: :runtime
|
90
|
+
version_requirements: *id005
|
91
|
+
description: When mails or messages are sent from your application, Better Opener lets you preview the rendered messages in your browser instead of delivering them.
|
92
|
+
email:
|
93
|
+
- kai@doxter.de
|
94
|
+
executables: []
|
95
|
+
|
96
|
+
extensions: []
|
97
|
+
|
98
|
+
extra_rdoc_files: []
|
99
|
+
|
100
|
+
files:
|
101
|
+
- .gitignore
|
102
|
+
- Gemfile
|
103
|
+
- README.rdoc
|
104
|
+
- Rakefile
|
105
|
+
- better_opener.gemspec
|
106
|
+
- config.ru
|
107
|
+
- lib/better_opener.rb
|
108
|
+
- lib/better_opener/delivery_method.rb
|
109
|
+
- lib/better_opener/email.html.erb
|
110
|
+
- lib/better_opener/railtie.rb
|
111
|
+
- lib/better_opener/server.rb
|
112
|
+
- lib/better_opener/server/views/atom.haml
|
113
|
+
- lib/better_opener/server/views/index.haml
|
114
|
+
- lib/better_opener/server/views/show.haml
|
115
|
+
- lib/better_opener/sms.html.erb
|
116
|
+
- lib/better_opener/sms_gateway_adapter.rb
|
117
|
+
- lib/better_opener/version.rb
|
118
|
+
- lib/test.ru
|
119
|
+
homepage: http://github.com/learnjin/better_opener
|
120
|
+
licenses: []
|
121
|
+
|
122
|
+
post_install_message:
|
123
|
+
rdoc_options: []
|
124
|
+
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
hash: 3
|
133
|
+
segments:
|
134
|
+
- 0
|
135
|
+
version: "0"
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
hash: 3
|
142
|
+
segments:
|
143
|
+
- 0
|
144
|
+
version: "0"
|
145
|
+
requirements: []
|
146
|
+
|
147
|
+
rubyforge_project: better_opener
|
148
|
+
rubygems_version: 1.8.10
|
149
|
+
signing_key:
|
150
|
+
specification_version: 3
|
151
|
+
summary: A better way of Previewing mail in your browser instead of sending it.
|
152
|
+
test_files: []
|
153
|
+
|