Skip to content

Commit

Permalink
Initial commit, 0.0.1 release.
Browse files Browse the repository at this point in the history
  • Loading branch information
Cyril David committed Nov 28, 2010
0 parents commit 3098591
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
/pkg
19 changes: 19 additions & 0 deletions LICENSE
@@ -0,0 +1,19 @@
Copyright (c) 2010 Cyril David

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
32 changes: 32 additions & 0 deletions README.markdown
@@ -0,0 +1,32 @@
Originally taken from my initial draft [here][blogpost].

[blogpost]: http://www.pipetodevnull.com/past/2010/11/27/simple_mailer/

## USAGE

$ gem install malone

require "malone"

# typically you would do this somewhere in the bootstrapping
# part of your application

Malone.configure(
host: "smtp.gmail.com",
port: 587,
tls: true,
domain: "mydomain.com",
user: "me@mydomain.com",
pass: "mypass",
auth: :login,
from: "no-reply@mydomain.com"
)

Malone.deliver(from: "me@me.com", to: "you@me.com",
subject: "Test subject", body: "Great!")

That's it!

## LICENSE

MIT
48 changes: 48 additions & 0 deletions lib/malone.rb
@@ -0,0 +1,48 @@
require "net/smtp"
require "ostruct"
require "mailfactory"

class Malone
VERSION = "0.0.1"

attr :envelope

def self.deliver(params = {})
new(params).deliver
end

def self.configure(hash)
@config = OpenStruct.new(hash)
end

def self.config
@config
end

def initialize(params = {})
@envelope = MailFactory.new
@envelope.from = params[:from]
@envelope.to = params[:to]
@envelope.text = params[:body]
@envelope.subject = params[:subject]
end

def deliver
smtp = Net::SMTP.new config.host, config.port
smtp.enable_starttls if config.tls

begin
smtp.start(config.domain, config.user, config.pass, config.auth)
smtp.send_message(envelope.to_s, envelope.from.first, envelope.to)
ensure
smtp.finish
end
end

private
NotConfigured = Class.new(StandardError)

def config
self.class.config or raise(NotConfigured)
end
end
20 changes: 20 additions & 0 deletions malone.gemspec
@@ -0,0 +1,20 @@
Gem::Specification.new do |s|
s.name = 'malone'
s.version = "0.0.1"
s.summary = %{Dead-simple Ruby mailing solution that always delivers.}
s.date = "2010-11-28"
s.author = "Cyril David"
s.email = "cyx@pipetodevnull.com"
s.homepage = "http://github.com/cyx/malone"

s.specification_version = 2 if s.respond_to? :specification_version=

s.files = ["lib/malone.rb", "README.markdown", "LICENSE", "test/helper.rb", "test/malone_test.rb"]

s.require_paths = ['lib']

s.add_dependency "mailfactory"
s.add_development_dependency "cutest"
s.add_development_dependency "flexmock"
s.has_rdoc = false
end
28 changes: 28 additions & 0 deletions malone.gemspec.erb
@@ -0,0 +1,28 @@
<%- require "./lib/malone" -%>
<%- require "date" -%>
Gem::Specification.new do |s|
s.name = 'malone'
s.version = "<%= Malone::VERSION %>"
s.summary = %{Dead-simple Ruby mailing solution that always delivers.}
s.date = "<%= Date.today.to_s %>"
s.author = "Cyril David"
s.email = "cyx@pipetodevnull.com"
s.homepage = "http://github.com/cyx/malone"

s.specification_version = 2 if s.respond_to? :specification_version=

s.files = <%= Dir[
"lib/**/*.rb",
"README*",
"LICENSE",
"Rakefile",
"test/**/*.*"
].inspect %>

s.require_paths = ['lib']

s.add_dependency "mailfactory"
s.add_development_dependency "cutest"
s.add_development_dependency "flexmock"
s.has_rdoc = false
end
53 changes: 53 additions & 0 deletions test/helper.rb
@@ -0,0 +1,53 @@
require "cutest"
require "flexmock/base"

require File.expand_path("../lib/malone", File.dirname(__FILE__))

class FlexMock
class CutestFrameworkAdapter
def assert_block(msg, &block)
unless yield
puts msg
flunk(7)
end
end

def assert_equal(a, b, msg=nil)
flunk unless a == b
end

class AssertionFailedError < StandardError; end

def assertion_failed_error
Cutest::AssertionFailed
end
end

@framework_adapter = CutestFrameworkAdapter.new
end

module Cutest::Flexmocked
def test(*args, &block)
super

flexmock_verify
ensure
flexmock_close
end
end

class Cutest::Scope
include FlexMock::ArgumentTypes
include FlexMock::MockContainer

include Cutest::Flexmocked
end

module Kernel
def flunk(offset = 1)
exception = Cutest::AssertionFailed.new
exception.set_backtrace([caller[offset]])

raise exception
end
end
121 changes: 121 additions & 0 deletions test/malone_test.rb
@@ -0,0 +1,121 @@
require File.expand_path("helper", File.dirname(__FILE__))

setup do
m = Malone.new(from: "me@me.com", to: "you@me.com",
body: "FooBar", subject: "Hello World")
end

test "envelope" do |m|
assert m.envelope.from == ["me@me.com"]
assert m.envelope.to == ["you@me.com"]

assert m.envelope.instance_variable_get(:@text) == "FooBar"
assert m.envelope.get_header("subject") == ["=?utf-8?Q?Hello_World?="]
end

test "delivering with no config" do |m|
assert_raise Malone::NotConfigured do
m.deliver
end
end

test "configuring" do
Malone.configure(
host: "smtp.gmail.com",
port: 587,
domain: "mydomain.com",
tls: true,
user: "me@mydomain.com",
pass: "mypass",
auth: :login
)

assert Malone.config.host == "smtp.gmail.com"
assert Malone.config.port == 587
assert Malone.config.domain == "mydomain.com"
assert Malone.config.tls == true
assert Malone.config.user == "me@mydomain.com"
assert Malone.config.pass == "mypass"
assert Malone.config.auth == :login
end

scope do
setup do
Malone.configure(
host: "smtp.gmail.com",
port: 587,
domain: "mydomain.com",
tls: true,
user: "me@mydomain.com",
pass: "mypass",
auth: :login
)
end

test "delivering successfully" do
malone = Malone.new(to: "you@me.com", from: "me@me.com",
subject: "My subject", body: "My body")

# Let's begin the mocking fun
sender = flexmock("smtp sender")

# We start out by capturing the Net::SMTP.new part
flexmock(Net::SMTP).should_receive(:new).and_return(sender)

# Since we configured it with tls: true, then enable_starttls
# should be called
sender.should_receive(:enable_starttls).once

# Now we verify that start was indeed called exactly with the arguments
# we passed in
sender.should_receive(:start).once.with(
"mydomain.com", "me@mydomain.com", "mypass", :login,
)

# This is a bit of a hack, since envelope.to_s changes everytime.
# Specifically, The Message-ID part changes.
envelope_to_s = malone.envelope.to_s

# So we get one result of envelope.to_s
flexmock(malone.envelope).should_receive(:to_s).and_return(envelope_to_s)

# And then we make sure that that value of envelope.to_s is used
# instead of making it generate a new Message-ID
sender.should_receive(:send_message).once.with(
envelope_to_s, "me@me.com", ["you@me.com"]
).and_return("OK")

# I think this is important, otherwise the connection to the
# smtp server won't be closed properly
sender.should_receive(:finish).once

# One important part of the API of malone is that deliver
# should return the result of Net::SMTP#send_message.
assert "OK" == malone.deliver
end

test "delivering and failing" do
malone = Malone.new(to: "you@me.com", from: "me@me.com",
subject: "My subject", body: "My body")

# This is more or less the same example as above,
# except that here we make send_message fail
# and verify that finish is still called
sender = flexmock("smtp sender")

flexmock(Net::SMTP).should_receive(:new).and_return(sender)

sender.should_receive(:enable_starttls).once

sender.should_receive(:start).once.with(
"mydomain.com", "me@mydomain.com", "mypass", :login,
)

sender.should_receive(:send_message).once.and_raise(StandardError)
sender.should_receive(:finish).once

assert_raise StandardError do
assert nil == malone.deliver
end
end
end

0 comments on commit 3098591

Please sign in to comment.