freeswitcher 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +13 -0
- data/CHANGELOG +1140 -0
- data/MANIFEST +101 -0
- data/README +66 -70
- data/Rakefile +31 -77
- data/examples/{ies_demo.rb → inbound_event_socket.rb} +0 -1
- data/examples/{ies_demo_with_hook.rb → inbound_socket_events.rb} +1 -1
- data/examples/outbound_event_socket.rb +28 -0
- data/freeswitcher.gemspec +155 -0
- data/lib/fsr.rb +14 -4
- data/lib/fsr/listener/outbound.rb +21 -16
- data/lib/fsr/version.rb +3 -0
- data/spec/helper.rb +11 -6
- data/tasks/authors.rake +30 -0
- data/tasks/bacon.rake +66 -0
- data/tasks/changelog.rake +19 -0
- data/tasks/copyright.rake +21 -0
- data/tasks/gem.rake +23 -0
- data/tasks/gem_installer.rake +76 -0
- data/tasks/install_dependencies.rake +6 -0
- data/tasks/manifest.rake +4 -0
- data/tasks/rcov.rake +23 -0
- data/tasks/release.rake +52 -0
- data/tasks/reversion.rake +8 -0
- data/tasks/setup.rake +16 -0
- data/tasks/spec.rake +0 -59
- data/tasks/yard.rake +4 -0
- metadata +124 -112
- data/examples/dtmf_test.rb +0 -35
- data/examples/oes_demo.rb +0 -21
- data/examples/play_and_get_test.rb +0 -35
- data/tasks/package.rake +0 -29
- data/tasks/ride.rake +0 -6
- data/tasks/rspec.rake +0 -21
@@ -0,0 +1,155 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{freeswitcher}
|
5
|
+
s.version = "0.1.4"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Jayson Vaughn", "Michael Fellinger", "Kevin Berry", "TJ Vanderpoel"]
|
9
|
+
s.date = %q{2009-05-11}
|
10
|
+
s.description = %q{========================================================= FreeSWITCHeR Copyright (c) 2009 The Rubyists (Jayson Vaughn, Tj Vanderpoel, Michael Fellinger, Kevin Berry) Distributed under the terms of the MIT License. ========================================================== ABOUT ----- A ruby library for interacting with the "FreeSWITCH" (http://www.freeswitch.org) opensource telephony platform REQUIREMENTS ------------ - ruby (>= 1.8) - eventmachine (If you wish to use Outbound and Inbound listener) USAGE ----- An Outbound Event Listener Example that reads and returns DTMF input: -------------------------------------------------------------------- Simply just create a subclass of FSR::Listner::Outbound and all new calls/sessions will invoke the "session_initiated" callback method. * NOTE: FSR uses blocks within the 'session_inititated' method to ensure that the next "freeswich command" is not executed until the previous "Freeswitch command" has finished. This is kicked off by "answer do" require 'fsr' require 'fsr/listener/outbound' class OutboundDemo < FSR::Listener::Outbound def session_initiated exten = @session.headers[:caller_caller_id_number] FSR::Log.info "*** Answering incoming call from #{exten}" answer do FSR::Log.info "***Reading DTMF from #{exten}" read("/home/freeswitch/freeswitch/sounds/music/8000/sweet.wav", 4, 10, "input", 7000) do FSR::Log.info "*** Updating session for #{exten}" update_session do FSR::Log.info "***Success, grabbed #{@session.headers[:variable_input].strip} from #{exten}" hangup #Hangup the call end end end end end FSR.start_oes! OutboundDemo, :port => 8084, :host => "127.0.0.1" An Inbound Event Socket Listener example using FreeSWITCHeR's hook system: -------------------------------------------------------------------------- require 'pp' require 'fsr' require "fsr/listener/inbound" # EXAMPLE 1 # This adds a hook on CHANNEL_CREATE events. You can also create a method to handle the event you're after. See the next example FSL::Inbound.add_event_hook(:CHANNEL_CREATE) {|event| FSR::Log.info "*** [#{event.content[:unique_id]}] Channel created - greetings from the hook!" } # EXAMPLE 2 # Define a method to handle CHANNEL_HANGUP events. def custom_channel_hangup_handler(event) FSR::Log.info "*** [#{event.content[:unique_id]}] Channel hangup. The event:" pp event end # This adds a hook for EXAMPLE 2 FSL::Inbound.add_event_hook(:CHANNEL_HANGUP) {|event| custom_channel_hangup_handler(event) } # Start FSR Inbound Listener FSR.start_ies!(FSL::Inbound, :host => "localhost", :port => 8021) An Inbound Event Socket Listener example using the on_event callback method instead of hooks: --------------------------------------------------------------------------------------------- require 'pp' require 'fsr' require "fsr/listener/inbound" class IesDemo < FSR::Listener::Inbound def on_event(event) pp event.headers pp event.content[:event_name] end end FSR.start_ies!(IesDemo, :host => "localhost", :port => 8021) An example of using FSR::CommandSocket to originate a new call in irb: ---------------------------------------------------------------------- irb(main):001:0> require 'fsr' => true irb(main):002:0> FSR.load_all_commands => [:sofia, :originate] irb(main):003:0> sock = FSR::CommandSocket.new => #<FSR::CommandSocket:0xb7a89104 @server="127.0.0.1", @socket=#<TCPSocket:0xb7a8908c>, @port="8021", @auth="ClueCon"> irb(main):007:0> sock.originate(:target => 'sofia/gateway/carlos/8179395222', :endpoint => FSR::App::Bridge.new("user/bougyman")).run => {"Job-UUID"=>"732075a4-7dd5-4258-b124-6284a82a5ae7", "body"=>"", "Content-Type"=>"command/reply", "Reply-Text"=>"+OK Job-UUID: 732075a4-7dd5-4258-b124-6284a82a5ae7"} SUPPORT ------- Home page at http://code.rubyists.com/projects/fs #rubyists on FreeNode}
|
11
|
+
s.email = %q{FreeSWITCHeR@rubyists.com}
|
12
|
+
s.files = [".gitignore", "AUTHORS", "CHANGELOG", "License.txt", "MANIFEST", "NEWS", "README", "Rakefile", "examples/inbound_event_socket.rb", "examples/inbound_socket_events.rb", "examples/outbound_event_socket.rb", "freeswitcher.gemspec", "lib/fsr.rb", "lib/fsr/app.rb", "lib/fsr/app/answer.rb", "lib/fsr/app/bridge.rb", "lib/fsr/app/conference.rb", "lib/fsr/app/fifo.rb", "lib/fsr/app/fs_break.rb", "lib/fsr/app/fs_sleep.rb", "lib/fsr/app/hangup.rb", "lib/fsr/app/limit.rb", "lib/fsr/app/log.rb", "lib/fsr/app/play_and_get_digits.rb", "lib/fsr/app/playback.rb", "lib/fsr/app/read.rb", "lib/fsr/app/set.rb", "lib/fsr/app/speak.rb", "lib/fsr/app/transfer.rb", "lib/fsr/app/uuid_dump.rb", "lib/fsr/app/uuid_getvar.rb", "lib/fsr/app/uuid_setvar.rb", "lib/fsr/cmd.rb", "lib/fsr/cmd/calls.rb", "lib/fsr/cmd/fsctl.rb", "lib/fsr/cmd/originate.rb", "lib/fsr/cmd/sofia.rb", "lib/fsr/cmd/sofia/profile.rb", "lib/fsr/cmd/sofia/status.rb", "lib/fsr/cmd/sofia_contact.rb", "lib/fsr/cmd/status.rb", "lib/fsr/command_socket.rb", "lib/fsr/database.rb", "lib/fsr/database/call_limit.rb", "lib/fsr/database/core.rb", "lib/fsr/database/sofia_reg_external.rb", "lib/fsr/database/sofia_reg_internal.rb", "lib/fsr/database/voicemail_default.rb", "lib/fsr/event_socket.rb", "lib/fsr/fake_socket.rb", "lib/fsr/listener.rb", "lib/fsr/listener/header_and_content_response.rb", "lib/fsr/listener/inbound.rb", "lib/fsr/listener/inbound/event.rb", "lib/fsr/listener/outbound.rb", "lib/fsr/listener/outbound.rb.orig", "lib/fsr/model/call.rb", "lib/fsr/version.rb", "tasks/authors.rake", "tasks/bacon.rake", "tasks/changelog.rake", "tasks/copyright.rake", "tasks/gem.rake", "tasks/gem_installer.rake", "tasks/install_dependencies.rake", "tasks/manifest.rake", "tasks/rcov.rake", "tasks/release.rake", "tasks/reversion.rake", "tasks/setup.rake", "tasks/spec.rake", "tasks/yard.rake", "spec/helper.rb", "spec/fsr/app.rb", "spec/fsr/app/bridge.rb", "spec/fsr/app/conference.rb", "spec/fsr/app/fifo.rb", "spec/fsr/app/hangup.rb", "spec/fsr/app/limit.rb", "spec/fsr/app/log.rb", "spec/fsr/app/play_and_get_digits.rb", "spec/fsr/app/playback.rb", "spec/fsr/app/set.rb", "spec/fsr/app/transfer.rb", "spec/fsr/cmd.rb", "spec/fsr/cmd/calls.rb", "spec/fsr/cmd/originate.rb", "spec/fsr/cmd/sofia.rb", "spec/fsr/cmd/sofia/profile.rb", "spec/fsr/listener.rb", "spec/fsr/listener/inbound.rb", "spec/fsr/listener/outbound.rb", "spec/fsr/loading.rb"]
|
13
|
+
s.homepage = %q{http://code.rubyists.com/projects/fs}
|
14
|
+
s.post_install_message = %q{=========================================================
|
15
|
+
FreeSWITCHeR
|
16
|
+
Copyright (c) 2009 The Rubyists (Jayson Vaughn, Tj Vanderpoel, Michael Fellinger, Kevin Berry)
|
17
|
+
Distributed under the terms of the MIT License.
|
18
|
+
==========================================================
|
19
|
+
|
20
|
+
ABOUT
|
21
|
+
-----
|
22
|
+
A ruby library for interacting with the "FreeSWITCH" (http://www.freeswitch.org) opensource telephony platform
|
23
|
+
|
24
|
+
REQUIREMENTS
|
25
|
+
------------
|
26
|
+
- ruby (>= 1.8)
|
27
|
+
- eventmachine (If you wish to use Outbound and Inbound listener)
|
28
|
+
|
29
|
+
USAGE
|
30
|
+
-----
|
31
|
+
|
32
|
+
An Outbound Event Listener Example that reads and returns DTMF input:
|
33
|
+
--------------------------------------------------------------------
|
34
|
+
|
35
|
+
Simply just create a subclass of FSR::Listner::Outbound and all
|
36
|
+
new calls/sessions will invoke the "session_initiated" callback method.
|
37
|
+
|
38
|
+
* NOTE: FSR uses blocks within the 'session_inititated' method to ensure
|
39
|
+
that the next "freeswich command" is not executed until the previous
|
40
|
+
"Freeswitch command" has finished. This is kicked off by "answer do"
|
41
|
+
|
42
|
+
require 'fsr'
|
43
|
+
require 'fsr/listener/outbound'
|
44
|
+
|
45
|
+
class OutboundDemo < FSR::Listener::Outbound
|
46
|
+
|
47
|
+
def session_initiated
|
48
|
+
exten = @session.headers[:caller_caller_id_number]
|
49
|
+
FSR::Log.info "*** Answering incoming call from #{exten}"
|
50
|
+
|
51
|
+
answer do
|
52
|
+
FSR::Log.info "***Reading DTMF from #{exten}"
|
53
|
+
read("/home/freeswitch/freeswitch/sounds/music/8000/sweet.wav", 4, 10, "input", 7000) do
|
54
|
+
FSR::Log.info "*** Updating session for #{exten}"
|
55
|
+
update_session do
|
56
|
+
FSR::Log.info "***Success, grabbed #{@session.headers[:variable_input].strip} from #{exten}"
|
57
|
+
hangup #Hangup the call
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
FSR.start_oes! OutboundDemo, :port => 8084, :host => "127.0.0.1"
|
67
|
+
|
68
|
+
|
69
|
+
An Inbound Event Socket Listener example using FreeSWITCHeR's hook system:
|
70
|
+
--------------------------------------------------------------------------
|
71
|
+
|
72
|
+
require 'pp'
|
73
|
+
require 'fsr'
|
74
|
+
require "fsr/listener/inbound"
|
75
|
+
|
76
|
+
# EXAMPLE 1
|
77
|
+
# This adds a hook on CHANNEL_CREATE events. You can also create a method to handle the event you're after. See the next example
|
78
|
+
FSL::Inbound.add_event_hook(:CHANNEL_CREATE) {|event| FSR::Log.info "*** [#{event.content[:unique_id]}] Channel created - greetings from the hook!" }
|
79
|
+
|
80
|
+
# EXAMPLE 2
|
81
|
+
# Define a method to handle CHANNEL_HANGUP events.
|
82
|
+
def custom_channel_hangup_handler(event)
|
83
|
+
FSR::Log.info "*** [#{event.content[:unique_id]}] Channel hangup. The event:"
|
84
|
+
pp event
|
85
|
+
end
|
86
|
+
|
87
|
+
# This adds a hook for EXAMPLE 2
|
88
|
+
FSL::Inbound.add_event_hook(:CHANNEL_HANGUP) {|event| custom_channel_hangup_handler(event) }
|
89
|
+
|
90
|
+
|
91
|
+
# Start FSR Inbound Listener
|
92
|
+
FSR.start_ies!(FSL::Inbound, :host => "localhost", :port => 8021)
|
93
|
+
|
94
|
+
|
95
|
+
An Inbound Event Socket Listener example using the on_event callback method instead of hooks:
|
96
|
+
---------------------------------------------------------------------------------------------
|
97
|
+
|
98
|
+
require 'pp'
|
99
|
+
require 'fsr'
|
100
|
+
require "fsr/listener/inbound"
|
101
|
+
|
102
|
+
|
103
|
+
class IesDemo < FSR::Listener::Inbound
|
104
|
+
|
105
|
+
def on_event(event)
|
106
|
+
pp event.headers
|
107
|
+
pp event.content[:event_name]
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
FSR.start_ies!(IesDemo, :host => "localhost", :port => 8021)
|
113
|
+
|
114
|
+
|
115
|
+
An example of using FSR::CommandSocket to originate a new call in irb:
|
116
|
+
----------------------------------------------------------------------
|
117
|
+
|
118
|
+
irb(main):001:0> require 'fsr'
|
119
|
+
=> true
|
120
|
+
|
121
|
+
irb(main):002:0> FSR.load_all_commands
|
122
|
+
=> [:sofia, :originate]
|
123
|
+
|
124
|
+
irb(main):003:0> sock = FSR::CommandSocket.new
|
125
|
+
=> #<FSR::CommandSocket:0xb7a89104 @server="127.0.0.1", @socket=#<TCPSocket:0xb7a8908c>, @port="8021", @auth="ClueCon">
|
126
|
+
|
127
|
+
irb(main):007:0> sock.originate(:target => 'sofia/gateway/carlos/8179395222', :endpoint => FSR::App::Bridge.new("user/bougyman")).run
|
128
|
+
=> {"Job-UUID"=>"732075a4-7dd5-4258-b124-6284a82a5ae7", "body"=>"", "Content-Type"=>"command/reply", "Reply-Text"=>"+OK Job-UUID: 732075a4-7dd5-4258-b124-6284a82a5ae7"}
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
SUPPORT
|
133
|
+
-------
|
134
|
+
Home page at http://code.rubyists.com/projects/fs
|
135
|
+
#rubyists on FreeNode
|
136
|
+
}
|
137
|
+
s.require_paths = ["lib"]
|
138
|
+
s.rubyforge_project = %q{freeswitcher}
|
139
|
+
s.rubygems_version = %q{1.3.1}
|
140
|
+
s.summary = %q{A library for interacting with the "FreeSWITCH":http://freeswitch.org telephony platform}
|
141
|
+
s.test_files = ["spec/fsr/app.rb", "spec/fsr/app/bridge.rb", "spec/fsr/app/conference.rb", "spec/fsr/app/fifo.rb", "spec/fsr/app/hangup.rb", "spec/fsr/app/limit.rb", "spec/fsr/app/log.rb", "spec/fsr/app/play_and_get_digits.rb", "spec/fsr/app/playback.rb", "spec/fsr/app/set.rb", "spec/fsr/app/transfer.rb", "spec/fsr/cmd.rb", "spec/fsr/cmd/calls.rb", "spec/fsr/cmd/originate.rb", "spec/fsr/cmd/sofia.rb", "spec/fsr/cmd/sofia/profile.rb", "spec/fsr/listener.rb", "spec/fsr/listener/inbound.rb", "spec/fsr/listener/outbound.rb", "spec/fsr/loading.rb"]
|
142
|
+
|
143
|
+
if s.respond_to? :specification_version then
|
144
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
145
|
+
s.specification_version = 2
|
146
|
+
|
147
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
148
|
+
s.add_runtime_dependency(%q<eventmachine>, [">= 0"])
|
149
|
+
else
|
150
|
+
s.add_dependency(%q<eventmachine>, [">= 0"])
|
151
|
+
end
|
152
|
+
else
|
153
|
+
s.add_dependency(%q<eventmachine>, [">= 0"])
|
154
|
+
end
|
155
|
+
end
|
data/lib/fsr.rb
CHANGED
@@ -3,11 +3,15 @@ require 'socket'
|
|
3
3
|
require 'pathname'
|
4
4
|
require 'pp'
|
5
5
|
|
6
|
+
# Author:: TJ Vanderpoel (mailto:bougy.man@gmail.com)
|
7
|
+
# Copyright:: Copyright (c) 2009 The Rubyists (Jayson Vaughn, TJ Vanderpoel, Michael Fellinger, Kevin Berry)
|
8
|
+
# License:: Distributes under the terms of the MIT License http://www.opensource.org/licenses/mit-license.php
|
9
|
+
|
10
|
+
## This module declares the namespace under which the freeswitcher framework
|
11
|
+
## Any constants will be defined here, as well as methods for loading commands and applications
|
6
12
|
module FSR
|
7
13
|
# Global configuration options
|
8
|
-
|
9
|
-
VERSION = '0.1.3'
|
10
|
-
FS_INSTALL_PATHS = ["/usr/local/freeswitch", "/opt/freeswitch", "/usr/freeswitch"]
|
14
|
+
FS_INSTALL_PATHS = ["/usr/local/freeswitch", "/opt/freeswitch", "/usr/freeswitch", "/home/freeswitch/freeswitch"]
|
11
15
|
DEFAULT_CALLER_ID_NUMBER = '8675309'
|
12
16
|
DEFAULT_CALLER_ID_NAME = "FSR"
|
13
17
|
|
@@ -48,8 +52,13 @@ module FSR
|
|
48
52
|
end
|
49
53
|
|
50
54
|
# Method to start EM for Inbound Event Socket
|
55
|
+
# @see FSR::Listener::Inbound
|
56
|
+
# @param [FSR::Listener::Inbound] klass An Inbound Listener class, to be started by EM.run
|
57
|
+
# @param [::Hash] args A hash of options, may contain
|
58
|
+
# <tt>:host [String]</tt> The host/ip to bind to (Default: "localhost")
|
59
|
+
# <tt>:port [Integer]</tt> the port to listen on (Default: 8021)
|
51
60
|
def self.start_ies!(klass, args = {})
|
52
|
-
port = args[:port] ||
|
61
|
+
port = args[:port] || 8021
|
53
62
|
host = args[:host] || "localhost"
|
54
63
|
EM.run do
|
55
64
|
EventMachine::connect(host, port, klass)
|
@@ -83,4 +92,5 @@ module FSR
|
|
83
92
|
FS_CONFIG_PATH = FS_DB_PATH = nil
|
84
93
|
end
|
85
94
|
end
|
95
|
+
require "fsr/version"
|
86
96
|
|
@@ -13,7 +13,13 @@ module FSR
|
|
13
13
|
include FSR::App
|
14
14
|
|
15
15
|
# Redefine the FSR::App methods to wrap sendmsg around them
|
16
|
-
SENDMSG_METHOD_DEFINITION =
|
16
|
+
SENDMSG_METHOD_DEFINITION = [
|
17
|
+
"def %s(*args, &block)",
|
18
|
+
" sendmsg super",
|
19
|
+
" @queue << block if block_given?",
|
20
|
+
"end"
|
21
|
+
].join("\n")
|
22
|
+
|
17
23
|
APPLICATIONS.each { |app, obj| module_eval(SENDMSG_METHOD_DEFINITION % app.to_s) }
|
18
24
|
|
19
25
|
# session_initiated is called when a @session is first created.
|
@@ -48,8 +54,9 @@ module FSR
|
|
48
54
|
|
49
55
|
# Update_session
|
50
56
|
|
51
|
-
def update_session
|
57
|
+
def update_session(&block)
|
52
58
|
send_data("api uuid_dump #{@session.headers[:unique_id]}\n\n")
|
59
|
+
@queue << block if block_given?
|
53
60
|
end
|
54
61
|
|
55
62
|
def next_step
|
@@ -60,20 +67,20 @@ module FSR
|
|
60
67
|
protected
|
61
68
|
def post_init
|
62
69
|
@session = nil # holds the session object
|
63
|
-
@
|
70
|
+
@queue = [] # Keep track of queue for state machine
|
64
71
|
send_data("connect\n\n")
|
65
72
|
FSR::Log.debug "Accepting connections."
|
66
73
|
end
|
67
74
|
|
68
75
|
# receive_request is called each time data is received by the event machine
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
76
|
+
# it will manipulate the received data into either a new session or a reply,
|
77
|
+
# to be picked up by #session_initiated or #receive_reply.
|
78
|
+
# If your listener is listening for events, this will also renew your @session
|
79
|
+
# each time you receive a CHANNEL_DATA event.
|
73
80
|
# @param header The header of the request, as passed by HeaderAndContentProtocol
|
74
81
|
# @param content The content of the request, as passed by HeaderAndContentProtocol
|
75
82
|
#
|
76
|
-
# @
|
83
|
+
# @return [HeaderAndContentResponse] An EventMachine HeaderAndContentResponse
|
77
84
|
def receive_request(header, content)
|
78
85
|
hash_header = headers_2_hash(header)
|
79
86
|
hash_content = headers_2_hash(content)
|
@@ -82,26 +89,24 @@ module FSR
|
|
82
89
|
if @session.nil?
|
83
90
|
@session = session_header_and_content
|
84
91
|
@step = 0
|
92
|
+
@state = [:uninitiated]
|
85
93
|
session_initiated
|
94
|
+
@state << :initiated
|
86
95
|
elsif session_header_and_content.content[:event_name] # If content includes an event_name, it must be a response from an api command
|
87
96
|
if session_header_and_content.content[:event_name].to_s.match(/CHANNEL_DATA/i) # Anytime we see CHANNEL_DATA event, we want to update our @session
|
88
97
|
session_header_and_content = HeaderAndContentResponse.new({:headers => hash_header.merge(hash_content.strip_value_newlines), :content => {}})
|
89
98
|
@session = session_header_and_content
|
90
|
-
@step += 1
|
91
|
-
@
|
99
|
+
@step += 1 if @state.include?(:initiated)
|
100
|
+
@queue.pop.call unless @queue.empty?
|
92
101
|
receive_reply(hash_header)
|
93
102
|
end
|
94
103
|
else
|
95
|
-
@step += 1
|
96
|
-
@
|
104
|
+
@step += 1 if @state.include?(:initiated)
|
105
|
+
@queue.pop.call unless @queue.empty?
|
97
106
|
receive_reply(session_header_and_content)
|
98
107
|
end
|
99
108
|
end
|
100
109
|
|
101
|
-
def cmd(&block)
|
102
|
-
@stack << block
|
103
|
-
end
|
104
|
-
|
105
110
|
end
|
106
111
|
end
|
107
112
|
end
|
data/lib/fsr/version.rb
ADDED
data/spec/helper.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
begin
|
2
2
|
require 'bacon'
|
3
3
|
rescue LoadError
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
EOS
|
9
|
-
|
4
|
+
begin
|
5
|
+
require "rubygems"
|
6
|
+
require "bacon"
|
7
|
+
rescue LoadError
|
8
|
+
puts <<-EOS
|
9
|
+
To run these tests you must install bacon.
|
10
|
+
Quick and easy install for gem:
|
11
|
+
gem install bacon
|
12
|
+
EOS
|
13
|
+
exit(0)
|
14
|
+
end
|
10
15
|
end
|
11
16
|
|
12
17
|
Bacon.summary_on_exit
|
data/tasks/authors.rake
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Once git has a fix for the glibc in handling .mailmap and another fix for
|
2
|
+
# allowing empty mail address to be mapped in .mailmap we won't have to handle
|
3
|
+
# them manually.
|
4
|
+
|
5
|
+
desc 'Update AUTHORS'
|
6
|
+
task :authors do
|
7
|
+
authors = Hash.new(0)
|
8
|
+
|
9
|
+
`git shortlog -nse`.scan(/(\d+)\s(.+)\s<(.*)>$/) do |count, name, email|
|
10
|
+
case name
|
11
|
+
when "bougyman"
|
12
|
+
name, email = "TJ Vanderpoel", "bougy.man@gmail.com"
|
13
|
+
when /riscfuture/i
|
14
|
+
name, email = "Tim Morgan", "riscfuture@gmail.com"
|
15
|
+
when "Michael Fellinger m.fellinger@gmail.com"
|
16
|
+
name, email = "Michael Fellinger", "m.fellinger@gmail.com"
|
17
|
+
end
|
18
|
+
|
19
|
+
authors[[name, email]] += count.to_i
|
20
|
+
end
|
21
|
+
|
22
|
+
File.open('AUTHORS', 'w+') do |io|
|
23
|
+
io.puts "Following persons have contributed to #{GEMSPEC.name}."
|
24
|
+
io.puts '(Sorted by number of submitted patches, then alphabetically)'
|
25
|
+
io.puts ''
|
26
|
+
authors.sort_by{|(n,e),c| [-c, n.downcase] }.each do |(name, email), count|
|
27
|
+
io.puts("%6d %s <%s>" % [count, name, email])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/tasks/bacon.rake
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
desc 'Run all bacon specs with pretty output'
|
2
|
+
task :bacon => :install_dependencies do
|
3
|
+
require 'open3'
|
4
|
+
require 'scanf'
|
5
|
+
require 'matrix'
|
6
|
+
|
7
|
+
specs = PROJECT_SPECS
|
8
|
+
|
9
|
+
some_failed = false
|
10
|
+
specs_size = specs.size
|
11
|
+
len = specs.map{|s| s.size }.sort.last
|
12
|
+
total_tests = total_assertions = total_failures = total_errors = 0
|
13
|
+
totals = Vector[0, 0, 0, 0]
|
14
|
+
|
15
|
+
red, yellow, green = "\e[31m%s\e[0m", "\e[33m%s\e[0m", "\e[32m%s\e[0m"
|
16
|
+
left_format = "%4d/%d: %-#{len + 11}s"
|
17
|
+
spec_format = "%d specifications (%d requirements), %d failures, %d errors"
|
18
|
+
|
19
|
+
specs.each_with_index do |spec, idx|
|
20
|
+
print(left_format % [idx + 1, specs_size, spec])
|
21
|
+
|
22
|
+
Open3.popen3(RUBY, spec) do |sin, sout, serr|
|
23
|
+
out = sout.read.strip
|
24
|
+
err = serr.read.strip
|
25
|
+
|
26
|
+
# this is conventional, see spec/innate/state/fiber.rb for usage
|
27
|
+
if out =~ /^Bacon::Error: (needed .*)/
|
28
|
+
puts(yellow % ("%6s %s" % ['', $1]))
|
29
|
+
else
|
30
|
+
total = nil
|
31
|
+
|
32
|
+
out.each_line do |line|
|
33
|
+
scanned = line.scanf(spec_format)
|
34
|
+
|
35
|
+
next unless scanned.size == 4
|
36
|
+
|
37
|
+
total = Vector[*scanned]
|
38
|
+
break
|
39
|
+
end
|
40
|
+
|
41
|
+
if total
|
42
|
+
totals += total
|
43
|
+
tests, assertions, failures, errors = total_array = total.to_a
|
44
|
+
|
45
|
+
if tests > 0 && failures + errors == 0
|
46
|
+
puts((green % "%6d passed") % tests)
|
47
|
+
else
|
48
|
+
some_failed = true
|
49
|
+
puts(red % " failed")
|
50
|
+
puts out unless out.empty?
|
51
|
+
puts err unless err.empty?
|
52
|
+
end
|
53
|
+
else
|
54
|
+
some_failed = true
|
55
|
+
puts(red % " failed")
|
56
|
+
puts out unless out.empty?
|
57
|
+
puts err unless err.empty?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
total_color = some_failed ? red : green
|
64
|
+
puts(total_color % (spec_format % totals.to_a))
|
65
|
+
exit 1 if some_failed
|
66
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'time'
|
2
|
+
desc 'update changelog'
|
3
|
+
task :changelog do
|
4
|
+
File.open('CHANGELOG', 'w+') do |changelog|
|
5
|
+
`git log -z --abbrev-commit`.split("\0").each do |commit|
|
6
|
+
next if commit =~ /^Merge: \d*/
|
7
|
+
ref, author, time, _, title, _, message = commit.split("\n", 7)
|
8
|
+
ref = ref[/commit ([0-9a-f]+)/, 1]
|
9
|
+
author = author[/Author: (.*)/, 1].strip
|
10
|
+
time = Time.parse(time[/Date: (.*)/, 1]).utc
|
11
|
+
title.strip!
|
12
|
+
|
13
|
+
changelog.puts "[#{ref} | #{time}] #{author}"
|
14
|
+
changelog.puts '', " * #{title}"
|
15
|
+
changelog.puts '', message.rstrip if message
|
16
|
+
changelog.puts
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
desc "add copyright to all .rb files in the distribution"
|
2
|
+
task :copyright do
|
3
|
+
ignore = File.readlines('License.txt').
|
4
|
+
select{|line| line.strip!; File.exist?(line)}.
|
5
|
+
map{|file| File.expand_path(file)}
|
6
|
+
|
7
|
+
puts "adding copyright to files that don't have it currently"
|
8
|
+
puts PROJECT_COPYRIGHT
|
9
|
+
puts
|
10
|
+
|
11
|
+
Dir['{lib,test}/**/*{.rb}'].each do |file|
|
12
|
+
file = File.expand_path(file)
|
13
|
+
next if ignore.include? file
|
14
|
+
lines = File.readlines(file).map{|l| l.chomp}
|
15
|
+
unless lines.first(PROJECT_COPYRIGHT.size) == PROJECT_COPYRIGHT
|
16
|
+
puts "#{file} seems to need attention, first 4 lines:"
|
17
|
+
puts lines[0..3]
|
18
|
+
puts
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|