Permalink
Browse files

first commit

  • Loading branch information...
hsume2 committed Jul 22, 2011
0 parents commit aeba7fa3f8f9c59038671bf0a28d482e34015886
@@ -0,0 +1,5 @@
+lib/**/*.rb
+bin/*
+-
+features/**/*.feature
+LICENSE.txt
@@ -0,0 +1,48 @@
+# rcov generated
+coverage
+
+# rdoc generated
+rdoc
+
+# yard generated
+doc
+.yardoc
+
+# bundler
+.bundle
+
+# jeweler generated
+pkg
+
+# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
+#
+# * Create a file at ~/.gitignore
+# * Include files you want ignored
+# * Run: git config --global core.excludesfile ~/.gitignore
+#
+# After doing this, these files will be ignored in all your git projects,
+# saving you from having to 'pollute' every project you touch with them
+#
+# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
+#
+# For MacOS:
+#
+#.DS_Store
+
+# For TextMate
+#*.tmproj
+#tmtags
+
+# For emacs:
+#*~
+#\#*
+#.\#*
+
+# For vim:
+#*.swp
+
+# For redcar:
+#.redcar
+
+# For rubinius:
+#*.rbc
@@ -0,0 +1,5 @@
+infinity_test do
+ before_run do
+ clear :terminal
+ end
+end
1 .rvmrc
@@ -0,0 +1 @@
+rvm use ree-1.8.7-2011.03@twilio_flow
15 Gemfile
@@ -0,0 +1,15 @@
+source 'http://rubygems.org'
+
+group :development do
+ gem 'shoulda', '>= 0'
+ gem 'bundler', '~> 1.0.0'
+ gem 'jeweler', '~> 1.6.4'
+ gem 'rcov', '>= 0'
+ gem 'test-unit', :require => 'test/unit'
+ gem 'infinity_test'
+ gem 'actionpack', '~> 2.3.10'
+ gem 'mocha'
+end
+
+gem 'builder'
+gem 'state_machine'
@@ -0,0 +1,40 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ actionpack (2.3.12)
+ activesupport (= 2.3.12)
+ rack (~> 1.1.0)
+ activesupport (2.3.12)
+ builder (3.0.0)
+ git (1.2.5)
+ infinity_test (1.0.3)
+ notifiers (>= 1.1.0)
+ watchr (>= 0.7)
+ jeweler (1.6.4)
+ bundler (~> 1.0)
+ git (>= 1.2.5)
+ rake
+ mocha (0.9.12)
+ notifiers (1.1.0)
+ rack (1.1.2)
+ rake (0.9.2)
+ rcov (0.9.9)
+ shoulda (2.11.3)
+ state_machine (1.0.1)
+ test-unit (2.3.0)
+ watchr (0.7)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ actionpack (~> 2.3.10)
+ builder
+ bundler (~> 1.0.0)
+ infinity_test
+ jeweler (~> 1.6.4)
+ mocha
+ rcov
+ shoulda
+ state_machine
+ test-unit
@@ -0,0 +1,20 @@
+Copyright (c) 2011 Henry Hsu
+
+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.
133 README.md
@@ -0,0 +1,133 @@
+Call Center
+===========
+
+Support for defining call center workflows.
+
+Overview
+--------
+Call Center streamlines the process of defining multi-party call workflows in your application. Particularly, with [Twilio](http://www.twilio.com/docs) in mind.
+
+[Twilio](http://www.twilio.com/docs) provides a two-part API for managing phone calls, and is mostly driven by callbacks. Call Center DRYs up the application logic dealing with a callback driven API so you can focus on the business logic of your call center.
+
+### Not DRY
+Twilio requests your application to return [TwiML](http://www.twilio.com/docs/api/twiml/) that describes the call workflow. TwiML contains commands which Twilio then executes. It is essentially an application-to-application API, synonymous to making a REST call.
+
+In the context of "[Skinny Controller, Fat Model](http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model)", outgoing REST calls for the function of business logic are not a view concern but a model concern. Therefore, so is TwiML.
+
+Twilio supports callbacks URLs and redirects to URLs that also render TwiML as a method of modifying live calls. Incoming callbacks are handled by the controller first, but the response is still a model concern.
+
+Terminology
+-----------
+
+* **Call** - An application resource of yours that encapsulates a phone call. Phone calls are then acted on: answered, transferred, declined, etc.
+* **Event** - Is something that happens outside or inside your application in relation to a **Call**. Someone picks up, hangs up, presses a button, etc.
+* **State** - Is the status a **Call** is in which is descriptive of what's happened so far and what are the next things that should happen. (e.g. a call on hold is waiting for the agent to return)
+* **CallFlow** - Is a definition of the process a **Call** goes through. **Events** drive the flow between **States**. (e.g. a simple workflow is when noone answers the call, send the call to voicemail)
+* **Render** - Is the ability of the **CallFlow** to return TwiML to bring the call into the **State** or modify the live call through a **Redirect**.
+* **Redirect** - Is a way of modifying a live call outside of a TwiML response (e.g. background jobs)
+
+Usage
+-----
+
+ class Call
+ include CallCenter
+
+ call_flow :state, :intial => :answered do
+ state :answered do
+ event :incoming_call, :to => :voicemail, :if => :not_during_business_hours?
+ event :incoming_call, :to => :sales
+ end
+
+ state :voicemail do
+ event :customer_hangs_up, :to => :voicemail_completed
+ end
+
+ on_render(:sales) do |call, x|
+ x.Say "This is Sales!"
+ end
+
+ on_render(:voicemail) do |call, x|
+ x.Say "Leave a voicemail!"
+ end
+ end
+ end
+
+Flow
+----
+
+The general application flow for a **CallFlow** is like this:
+
+1. An incoming call is posted to your application
+ * You create a **Call**
+ * You execute an initial event
+ * You respond by rendering TwiML. Your TwiML contains callbacks to events or redirects
+2. Something happens and Twilio posts an event to your application
+ * You find the **Call**
+ * You store any new information
+ * You execute the posted event
+ * You respond by rendering TwiML. Your TwiML contains callbacks to events or redirects
+3. Repeat 2.
+
+Rendering
+---------
+
+Rendering is your way of interacting with Twilio. Thus, it provides two facilities: access to an XML builder and access to your call.
+
+ on_render(:sales) do |the_call, xml_builder|
+ xml_builder.Say "This is Sales!"
+
+ the_call.flag! # You can access the call explicitly
+ flag! # Or access it implicitly
+ end
+
+Renders:
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <Response>
+ <Say>This is Sales!</Say>
+ </Response>
+
+Redirects
+---------
+
+Redirects are a request made to the [Twilio REST API](http://www.twilio.com/docs/api/rest/) that points to a callback URL which returns TwiML to be executed on a call. It is up to you how you want to perform this (e.g. with your favority http libraries, or with [Twilio Libraries](http://www.twilio.com/docs/libraries/)).
+
+Redirect to events look like this:
+
+ ...
+ call_flow :state, :intial => :answered do
+ state :answered do
+ ...
+ end
+
+ state :ending_call do
+ event :end_call, :to => :ended_call
+ end
+
+ on_render(:ending_call) do
+ redirect_and_end_call!(:status => 'completed')
+ end
+ end
+ ...
+
+For your **Call** to support this syntax, it must adhere to the following API:
+
+ class Call
+ def redirect_to(event, *args)
+ # where:
+ # event #=> :end_call
+ # args #=> [:status => 'completed]
+ @account.calls.get(self.sid).update({:url => "http://myapp.com/call_flow?event=#{event}"})
+ end
+ end
+
+Tools
+-----
+
+### Drawing ###
+
+Benefits of **CallCenter** is that it's backed by [state_machine](https://github.com/pluginaweek/state_machine). Should you be interested in what your call center workflow looks like, you can draw.
+
+ Call.state_machines[:status].draw(:font => 'Helvetica Neue')
+ # OR
+ @call.draw_call_flow(:font => 'Helvetica Neue')
@@ -0,0 +1,53 @@
+# encoding: utf-8
+
+require 'rubygems'
+require 'bundler'
+begin
+ Bundler.setup(:default, :development)
+rescue Bundler::BundlerError => e
+ $stderr.puts e.message
+ $stderr.puts "Run `bundle install` to install missing gems"
+ exit e.status_code
+end
+require 'rake'
+
+require 'jeweler'
+Jeweler::Tasks.new do |gem|
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
+ gem.name = "call_center"
+ gem.homepage = "http://github.com/zendesk/call_center"
+ gem.license = "MIT"
+ gem.summary = %Q{Support for describing call center workflows}
+ gem.description = %Q{Support for describing call center workflows}
+ gem.email = "hhsu@zendesk.com"
+ gem.authors = ["Henry Hsu"]
+ # dependencies defined in Gemfile
+end
+Jeweler::RubygemsDotOrgTasks.new
+
+require 'rake/testtask'
+Rake::TestTask.new(:test) do |test|
+ test.libs << 'lib' << 'test'
+ test.pattern = 'test/**/test_*.rb'
+ test.verbose = true
+end
+
+require 'rcov/rcovtask'
+Rcov::RcovTask.new do |test|
+ test.libs << 'test'
+ test.pattern = 'test/**/*_test.rb'
+ test.verbose = true
+ test.rcov_opts << '--exclude "gems/*"'
+end
+
+task :default => :test
+
+require 'rake/rdoctask'
+Rake::RDocTask.new do |rdoc|
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
+
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = "twilio_flow #{version}"
+ rdoc.rdoc_files.include('README*')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
@@ -0,0 +1 @@
+0.0.1
@@ -0,0 +1,64 @@
+# Generated by jeweler
+# DO NOT EDIT THIS FILE DIRECTLY
+# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = %q{call_center}
+ s.version = "0.0.1"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Henry Hsu"]
+ s.date = %q{2011-07-22}
+ s.description = %q{Support for describing call center workflows}
+ s.email = %q{hhsu@zendesk.com}
+ s.extra_rdoc_files = [
+ "LICENSE.txt",
+ "README.md"
+ ]
+ s.homepage = %q{http://github.com/zendesk/call_center}
+ s.licenses = ["MIT"]
+ s.require_paths = ["lib"]
+ s.rubygems_version = %q{1.5.3}
+ s.summary = %q{Support for describing call center workflows}
+
+ if s.respond_to? :specification_version then
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+ s.add_runtime_dependency(%q<builder>, [">= 0"])
+ s.add_runtime_dependency(%q<state_machine>, [">= 0"])
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
+ s.add_development_dependency(%q<rcov>, [">= 0"])
+ s.add_development_dependency(%q<test-unit>, [">= 0"])
+ s.add_development_dependency(%q<infinity_test>, [">= 0"])
+ s.add_development_dependency(%q<actionpack>, ["~> 2.3.10"])
+ s.add_development_dependency(%q<mocha>, [">= 0"])
+ else
+ s.add_dependency(%q<builder>, [">= 0"])
+ s.add_dependency(%q<state_machine>, [">= 0"])
+ s.add_dependency(%q<shoulda>, [">= 0"])
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
+ s.add_dependency(%q<rcov>, [">= 0"])
+ s.add_dependency(%q<test-unit>, [">= 0"])
+ s.add_dependency(%q<infinity_test>, [">= 0"])
+ s.add_dependency(%q<actionpack>, ["~> 2.3.10"])
+ s.add_dependency(%q<mocha>, [">= 0"])
+ end
+ else
+ s.add_dependency(%q<builder>, [">= 0"])
+ s.add_dependency(%q<state_machine>, [">= 0"])
+ s.add_dependency(%q<shoulda>, [">= 0"])
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
+ s.add_dependency(%q<rcov>, [">= 0"])
+ s.add_dependency(%q<test-unit>, [">= 0"])
+ s.add_dependency(%q<infinity_test>, [">= 0"])
+ s.add_dependency(%q<actionpack>, ["~> 2.3.10"])
+ s.add_dependency(%q<mocha>, [">= 0"])
+ end
+end
+
Oops, something went wrong.

0 comments on commit aeba7fa

Please sign in to comment.