adhearsion 0.7.6 → 0.7.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.version +1 -1
- data/CHANGELOG +43 -25
- data/Rakefile +0 -5
- data/TODO +51 -2
- data/ahn +2 -1
- data/apps/default/Rakefile +16 -7
- data/apps/default/config/adhearsion.yml +22 -1
- data/apps/default/config/helpers/manager_proxy.yml +1 -0
- data/apps/default/config/helpers/micromenus/images/arrow-off.gif +0 -0
- data/apps/default/config/helpers/micromenus/images/arrow-on.gif +0 -0
- data/apps/default/config/helpers/micromenus/images/error.gif +0 -0
- data/apps/default/config/helpers/micromenus/images/folder-off.gif +0 -0
- data/apps/default/config/helpers/micromenus/images/folder-on.gif +0 -0
- data/apps/default/config/helpers/micromenus/images/folder.png +0 -0
- data/apps/default/config/helpers/micromenus/images/ggbridge.jpg +0 -0
- data/apps/default/config/helpers/micromenus/images/green.png +0 -0
- data/apps/default/config/helpers/micromenus/images/microbrowser.bg.gif +0 -0
- data/apps/default/config/helpers/micromenus/images/red.png +0 -0
- data/apps/default/config/helpers/micromenus/images/url-off.gif +0 -0
- data/apps/default/config/helpers/micromenus/images/url-on.gif +0 -0
- data/apps/default/config/helpers/micromenus/images/yellow.png +0 -0
- data/apps/default/config/helpers/micromenus/javascripts/animation.js +1341 -0
- data/apps/default/config/helpers/micromenus/javascripts/carousel.js +1238 -0
- data/apps/default/config/helpers/micromenus/javascripts/columnav.js +306 -0
- data/apps/default/config/helpers/micromenus/javascripts/connection.js +965 -0
- data/apps/default/config/helpers/micromenus/javascripts/container.js +4727 -0
- data/apps/default/config/helpers/micromenus/javascripts/container_core.js +2915 -0
- data/apps/default/config/helpers/micromenus/javascripts/dom.js +892 -0
- data/apps/default/config/helpers/micromenus/javascripts/dragdrop.js +2921 -907
- data/apps/default/config/helpers/micromenus/javascripts/event.js +1771 -0
- data/apps/default/config/helpers/micromenus/javascripts/yahoo.js +433 -0
- data/apps/default/config/helpers/micromenus/stylesheets/carousel.css +78 -0
- data/apps/default/config/helpers/micromenus/stylesheets/columnav.css +135 -0
- data/apps/default/config/helpers/micromenus/stylesheets/microbrowsers.css +42 -0
- data/apps/default/config/helpers/multi_messenger.yml +5 -1
- data/apps/default/config/migration.rb +10 -0
- data/apps/default/extensions.rb +1 -1
- data/apps/default/helpers/factorial.alien.c +3 -3
- data/apps/default/helpers/lookup.rb +2 -1
- data/apps/default/helpers/manager_proxy.rb +67 -15
- data/apps/default/helpers/micromenus.rb +173 -31
- data/apps/default/helpers/multi_messenger.rb +20 -3
- data/lib/adhearsion.rb +218 -88
- data/lib/constants.rb +1 -0
- data/lib/core_extensions.rb +15 -9
- data/lib/phone_number.rb +85 -0
- data/lib/rami.rb +3 -2
- data/lib/servlet_container.rb +47 -24
- data/lib/sexy_migrations.rb +70 -0
- data/test/asterisk_module_test.rb +9 -9
- data/test/specs/numerical_string_spec.rb +53 -0
- metadata +31 -11
- data/apps/default/config/helpers/micromenus/javascripts/builder.js +0 -131
- data/apps/default/config/helpers/micromenus/javascripts/controls.js +0 -834
- data/apps/default/config/helpers/micromenus/javascripts/effects.js +0 -956
- data/apps/default/config/helpers/micromenus/javascripts/prototype.js +0 -2319
- data/apps/default/config/helpers/micromenus/javascripts/scriptaculous.js +0 -51
- data/apps/default/config/helpers/micromenus/javascripts/slider.js +0 -278
- data/apps/default/config/helpers/micromenus/javascripts/unittest.js +0 -557
- data/apps/default/config/helpers/micromenus/stylesheets/firefox.css +0 -10
- data/apps/default/config/helpers/micromenus/stylesheets/firefox.xul.css +0 -44
data/lib/constants.rb
CHANGED
data/lib/core_extensions.rb
CHANGED
@@ -39,14 +39,6 @@ class Object
|
|
39
39
|
nil
|
40
40
|
end
|
41
41
|
|
42
|
-
def is_local_number?
|
43
|
-
to_s =~ LOCAL_NUMBER
|
44
|
-
end
|
45
|
-
|
46
|
-
def is_national_number?
|
47
|
-
to_s =~ US_NUMBER
|
48
|
-
end
|
49
|
-
|
50
42
|
def mutex() @mutex ||= Mutex.new end
|
51
43
|
def synchronize() mutex.synchronize { yield self } end
|
52
44
|
|
@@ -63,13 +55,15 @@ class Object
|
|
63
55
|
name = priority == :normal ? "AFTER_CALL" : "AFTER_CALL_#{priority.to_s.upcase}"
|
64
56
|
eval("$#{name}") << block
|
65
57
|
end
|
58
|
+
|
59
|
+
def segment(&block) block.call end
|
66
60
|
end
|
67
61
|
|
68
62
|
class String
|
69
63
|
|
70
64
|
def String.random_char
|
71
65
|
case r = rand(62)
|
72
|
-
when
|
66
|
+
when 0...10 then r.to_s
|
73
67
|
when 10...36 then (r+55).chr
|
74
68
|
when 36...62 then (r+61).chr
|
75
69
|
end
|
@@ -136,6 +130,8 @@ class Numeric
|
|
136
130
|
def =~ other
|
137
131
|
to_s =~ other
|
138
132
|
end
|
133
|
+
def length() to_s.length end
|
134
|
+
alias size length
|
139
135
|
|
140
136
|
def am() self end
|
141
137
|
def pm() self+12 end
|
@@ -148,6 +144,16 @@ class Numeric
|
|
148
144
|
end
|
149
145
|
end
|
150
146
|
|
147
|
+
class Integer
|
148
|
+
alias old_to_i to_i
|
149
|
+
# Allows 123.to_i(2) to work for base conversions.
|
150
|
+
def to_i base=nil
|
151
|
+
if base then to_s.to_i base
|
152
|
+
else self
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
151
157
|
class Time
|
152
158
|
def weekday?() (1..5).include? wday end
|
153
159
|
def weekend?() !weekday? end
|
data/lib/phone_number.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
class NumericalString
|
2
|
+
|
3
|
+
(instance_methods - %w"__id__ __send__ __real_num __real_string").each do |m|
|
4
|
+
undef_method m
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize str
|
8
|
+
@__real_string = str.to_s
|
9
|
+
@__real_num = str.to_i if @__real_string =~ /^\d+$/
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :__real_num, :__real_string
|
13
|
+
|
14
|
+
def method_missing name, *args, &block
|
15
|
+
@__real_string.__send__ name, *args, &block
|
16
|
+
end
|
17
|
+
|
18
|
+
def respond_to? m
|
19
|
+
@__real_string.respond_to?(m) || m == :__real_num || m == :__real_string
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
# The PhoneNumber class is used by one object throughout Adhearsion: the AGI
|
25
|
+
# "extension" variable. Using some clevery Ruby hackery, the Extension class allows
|
26
|
+
# dialplan writers to use the best of Fixnum and String usage such as
|
27
|
+
#
|
28
|
+
# - Dialing international numbers
|
29
|
+
# - Using a regexp in a case statement for "extension"
|
30
|
+
# - Using a numerical range against extension -- e.g. (100...200)
|
31
|
+
# - Using the thousands separator
|
32
|
+
class PhoneNumber < NumericalString
|
33
|
+
|
34
|
+
# Checks against a pattern identifying US local numbers (i.e numbers
|
35
|
+
# without an area code seven digits long)
|
36
|
+
def local_number?() to_s =~ LOCAL_NUMBER end
|
37
|
+
|
38
|
+
# Checks against a pattern identifying US domestic numbers.
|
39
|
+
def national_number?() to_s =~ US_NUMBER end
|
40
|
+
|
41
|
+
# Checks against a pattern identifying an ISN number. See http://freenum.org
|
42
|
+
# for more info.
|
43
|
+
def isn?() to_s =~ ISN end
|
44
|
+
|
45
|
+
# Useful for dialing those 1-800-FUDGEME type numbers with letters in them. Letters
|
46
|
+
# in the argument will be converted to their appropriate keypad key.
|
47
|
+
def self.from_vanity str
|
48
|
+
str.gsub(/\W/, '').upcase.tr('A-Z', '22233344455566677778889999')
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
class Object
|
54
|
+
|
55
|
+
alias _equalequalequal ===
|
56
|
+
|
57
|
+
def === arg
|
58
|
+
if arg.respond_to? :__real_string
|
59
|
+
arg = arg.__real_num if kind_of?(Numeric) || kind_of?(Range)
|
60
|
+
_equalequalequal arg
|
61
|
+
else
|
62
|
+
_equalequalequal arg
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class Range
|
68
|
+
alias _old_equalequalequal ===
|
69
|
+
def === arg
|
70
|
+
if arg.respond_to? :__real_string
|
71
|
+
arg = arg.__real_num if kind_of?(Numeric) || kind_of?(Range)
|
72
|
+
_old_equalequalequal arg
|
73
|
+
else
|
74
|
+
_old_equalequalequal arg
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class << String
|
80
|
+
# Had to do this for ActiveRecord compatability.
|
81
|
+
alias __equalequalequal ===
|
82
|
+
def === arg
|
83
|
+
arg.respond_to?(:__real_string) ? true : __equalequalequal(arg)
|
84
|
+
end
|
85
|
+
end
|
data/lib/rami.rb
CHANGED
@@ -215,7 +215,7 @@ class Client
|
|
215
215
|
'Exten' =>h['Exten'],
|
216
216
|
'Priority' =>h['Priority'],
|
217
217
|
'Timeout' =>h['Timeout'],
|
218
|
-
'CallerID' =>h['CallerID'],
|
218
|
+
'CallerID' =>h['Callerid'] || h['CallerID'],
|
219
219
|
'Variable' =>h['Variable'],
|
220
220
|
'Account' =>h['Account'],
|
221
221
|
'Application' =>h['Application'],
|
@@ -387,7 +387,8 @@ def connect
|
|
387
387
|
$HUTDOWN.now!
|
388
388
|
return
|
389
389
|
end
|
390
|
-
|
390
|
+
events = $HELPERS['manager_proxy']['events']
|
391
|
+
login = {'Action' => 'login', 'Username' => @username, 'Secret' => @secret, 'Events' => events ? 'On' : 'Off'}
|
391
392
|
writesock(login)
|
392
393
|
accum = {}
|
393
394
|
login = 0
|
data/lib/servlet_container.rb
CHANGED
@@ -17,7 +17,7 @@
|
|
17
17
|
|
18
18
|
class ServletContainer
|
19
19
|
|
20
|
-
# TODO: Port
|
20
|
+
# TODO: Port more efficient server here. Erlang perhaps?
|
21
21
|
class NativeServer;end
|
22
22
|
|
23
23
|
require 'gserver'
|
@@ -30,18 +30,38 @@ class ServletContainer
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def read_variables io
|
33
|
-
|
34
|
-
while
|
33
|
+
vars = {}
|
34
|
+
while line = io.gets.chomp
|
35
35
|
break if line.empty? # Empty lines signify no more variables
|
36
36
|
variable = line.split(/:\s*/)
|
37
37
|
new_name, new_value = variable.first[4..-1].downcase, variable.last
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
|
39
|
+
if new_name == 'extension' then vars['extension'] = PhoneNumber.new new_value
|
40
|
+
elsif new_name == 'context' then vars['context'] = new_value.gsub '-', '_'
|
41
|
+
elsif new_name == 'request'
|
42
|
+
uri = URI.parse new_value
|
43
|
+
query = {}
|
44
|
+
if uri.query
|
45
|
+
hash = {}
|
46
|
+
uri.query.split('&').each do |a|
|
47
|
+
k,v = a.split('=')
|
48
|
+
query[k] = v
|
49
|
+
end
|
50
|
+
context = query['context']
|
51
|
+
end
|
52
|
+
vars['request'], vars['uri'], vars['query'] = new_value, uri, query
|
53
|
+
else
|
54
|
+
vars[new_name.to_s] = if new_value =~ /^\d+$/
|
55
|
+
if new_value.starts_with?('0') then NumericalString.new(new_value)
|
56
|
+
else new_value.to_i
|
57
|
+
end
|
58
|
+
else new_value
|
59
|
+
end
|
41
60
|
end
|
42
|
-
|
61
|
+
|
43
62
|
end
|
44
|
-
|
63
|
+
vars['context'] = vars['query']['context'] if vars['query']['context']
|
64
|
+
vars
|
45
65
|
end
|
46
66
|
|
47
67
|
# GServer allows all functionality to be packed into this one serve() method.
|
@@ -70,7 +90,7 @@ class ServletContainer
|
|
70
90
|
end
|
71
91
|
|
72
92
|
log "Executing call with variables: " + call_variables.inspect
|
73
|
-
|
93
|
+
|
74
94
|
call_variables.each do |k,v|
|
75
95
|
Thread.current[:container].run_inside do
|
76
96
|
meta_def(k) { v }
|
@@ -78,17 +98,18 @@ class ServletContainer
|
|
78
98
|
end
|
79
99
|
|
80
100
|
# Execute all before_call hooks
|
81
|
-
[$
|
82
|
-
+lambda { answer if CONFIG
|
101
|
+
[$BEFORE_CALL_HIGH, $BEFORE_CALL, $BEFORE_CALL_LOW].flatten.compact.each(&:call)
|
102
|
+
+lambda { answer if CONFIG['answer_before_call'] }
|
83
103
|
|
84
104
|
# A call hook may decree that the call shouldn't be processed further (e.g. if
|
85
105
|
# it processed the call itself). This is done be rewriting the context variable.
|
86
106
|
unless Thread.current[:VARS]['context'] == :interrupted
|
87
|
-
|
107
|
+
|
88
108
|
begin
|
109
|
+
|
89
110
|
Contexts.new.instance_eval do
|
90
111
|
# Interpret the extensions.rb file!
|
91
|
-
eval File.read(
|
112
|
+
eval File.read("extensions.rb")
|
92
113
|
end
|
93
114
|
rescue => detail
|
94
115
|
log "Exception raised in extensions.rb! " << detail.message
|
@@ -98,21 +119,23 @@ class ServletContainer
|
|
98
119
|
|
99
120
|
log "Parsing of extensions.rb complete"
|
100
121
|
|
101
|
-
# Because Asterisk allows dashes in its context names and Ruby interprets
|
102
|
-
# these as minuses, let's convert them to underscores.
|
103
|
-
call_variables['context'].gsub! '-', '_'
|
104
|
-
|
105
122
|
begin
|
106
123
|
target_context = call_variables['context']
|
107
124
|
if target_context
|
108
125
|
Thread.current[:container].run_inside do
|
109
126
|
begin
|
110
|
-
|
127
|
+
unless target_context.kind_of? Proc
|
128
|
+
target_context = send(target_context.to_s.to_sym)
|
129
|
+
end
|
130
|
+
+target_context
|
131
|
+
rescue ControlPassingException => new_target
|
132
|
+
target_context = new_target.target
|
133
|
+
retry
|
111
134
|
rescue => e
|
112
135
|
error e.inspect + "\n " + e.backtrace * "\n "
|
113
136
|
+lambda {
|
114
|
-
play 'were-sorry'
|
115
|
-
hangup
|
137
|
+
play 'an-error-has-occurred', 'were-sorry'
|
138
|
+
hangup if CONFIG.key?('hangup_after_error') && CONFIG['hangup_after_error']
|
116
139
|
}
|
117
140
|
end
|
118
141
|
end
|
@@ -122,14 +145,14 @@ class ServletContainer
|
|
122
145
|
return
|
123
146
|
end
|
124
147
|
rescue => detail
|
125
|
-
|
126
|
-
detail.backtrace.each do |msg|
|
148
|
+
error "ERROR: #{detail.class.name} => #{detail.inspect}"
|
149
|
+
detail.backtrace.each do |msg| error " " * 8 << msg end
|
127
150
|
end
|
128
151
|
log "Call routing complete"
|
129
152
|
end
|
130
153
|
rescue => detail
|
131
|
-
|
132
|
-
detail.backtrace.each
|
154
|
+
error "Call thread raised an exception! #{detail.message}"
|
155
|
+
detail.backtrace.each { |msg| error " " * 8 << msg }
|
133
156
|
end
|
134
157
|
|
135
158
|
[$AFTER_CALL_HIGH, $AFTER_CALL, $AFTER_CALL_LOW].flatten.compact.each(&:call)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# Taken from svn://errtheblog.com/svn/plugins/sexy_migrations/lib/sexy_migrations.rb
|
2
|
+
module SexyMigrations
|
3
|
+
module Table
|
4
|
+
attr_reader :fk_references
|
5
|
+
|
6
|
+
def foreign_key(*args)
|
7
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
8
|
+
args.each do |col|
|
9
|
+
column(id = "#{col}_id", :integer, options)
|
10
|
+
(@fk_references ||= []) << [id, options[:ref].to_s] if options[:ref]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
alias :fkey :foreign_key
|
14
|
+
alias :fkeys :foreign_key
|
15
|
+
alias :foreign_keys :foreign_key
|
16
|
+
|
17
|
+
def timestamps(*extras)
|
18
|
+
(Array(extras) + %w(created_at updated_at)).each do |stamp|
|
19
|
+
datetime stamp
|
20
|
+
end
|
21
|
+
end
|
22
|
+
alias :timestamps! :timestamps
|
23
|
+
alias :auto_dates :timestamps
|
24
|
+
alias :auto_dates! :timestamps
|
25
|
+
|
26
|
+
def polymorphic(name)
|
27
|
+
integer "#{name}_id"
|
28
|
+
string "#{name}_type"
|
29
|
+
end
|
30
|
+
alias :polymorphic! :polymorphic
|
31
|
+
|
32
|
+
def method_missing(name, *args)
|
33
|
+
return super unless type = simplified_type(name)
|
34
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
35
|
+
args.each { |col| column(col, type, options) }
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def simplified_type(type)
|
40
|
+
ActiveRecord::ConnectionAdapters::Column.new(:type_check, false, type.to_s).type
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module Schema
|
45
|
+
def create_table(name, options = {}, &block)
|
46
|
+
table_definition = ActiveRecord::ConnectionAdapters::TableDefinition.new(self)
|
47
|
+
table_definition.primary_key(options[:primary_key] || "id") unless options[:id] == false
|
48
|
+
|
49
|
+
table_definition.instance_eval &block
|
50
|
+
|
51
|
+
if options[:force]
|
52
|
+
drop_table(name, options) rescue nil
|
53
|
+
end
|
54
|
+
|
55
|
+
create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
|
56
|
+
create_sql << "#{name} ("
|
57
|
+
create_sql << table_definition.to_sql
|
58
|
+
create_sql << ") #{options[:options]}"
|
59
|
+
|
60
|
+
# if any fk contraints, add them
|
61
|
+
if table_definition.fk_references
|
62
|
+
create_sql << "; "
|
63
|
+
table_definition.fk_references.each do |fk|
|
64
|
+
create_sql << "ALTER TABLE #{name} ADD FOREIGN KEY (#{fk[0]}) REFERENCES #{fk[1]} (id); "
|
65
|
+
end
|
66
|
+
end
|
67
|
+
execute create_sql
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
|
-
context "The
|
1
|
+
context "The PBX object" do
|
2
2
|
specify "should properize properly" do
|
3
|
-
properize("123").should == 'SIP/123'
|
4
|
-
properize(1_555_444_1234).should == 'SIP/15554441234'
|
5
|
-
properize(:jay).should == 'SIP/jay'
|
6
|
-
properize("jay").should == 'SIP/jay'
|
7
|
-
properize("SIP/123").should == 'SIP/123'
|
8
|
-
properize("IAX2/jay").should == 'IAX2/jay'
|
9
|
-
properize((100..110).to_a).should == 'SIP/100&SIP/101&SIP/102&SIP/103&SIP/104&SIP/105&SIP/106&SIP/107&SIP/108&SIP/109&SIP/110'
|
10
|
-
properize(["SIP/123", "SIP/456"]).should == 'SIP/123&SIP/456'
|
3
|
+
PBX.properize("123").should == 'SIP/123'
|
4
|
+
PBX.properize(1_555_444_1234).should == 'SIP/15554441234'
|
5
|
+
PBX.properize(:jay).should == 'SIP/jay'
|
6
|
+
PBX.properize("jay").should == 'SIP/jay'
|
7
|
+
PBX.properize("SIP/123").should == 'SIP/123'
|
8
|
+
PBX.properize("IAX2/jay").should == 'IAX2/jay'
|
9
|
+
PBX.properize((100..110).to_a).should == 'SIP/100&SIP/101&SIP/102&SIP/103&SIP/104&SIP/105&SIP/106&SIP/107&SIP/108&SIP/109&SIP/110'
|
10
|
+
PBX.properize(["SIP/123", "SIP/456"]).should == 'SIP/123&SIP/456'
|
11
11
|
# TODO: Should mock up dialing a user
|
12
12
|
# TODO: Should mock up dialing a group
|
13
13
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'phone_number.rb')
|
2
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'constants.rb')
|
3
|
+
|
4
|
+
context "A NumericalString" do
|
5
|
+
specify "should be accessable as a Fixnum to a case statement" do
|
6
|
+
(123 === NumericalString.new("123")).should == true
|
7
|
+
(987 === NumericalString.new("0987")).should == true
|
8
|
+
end
|
9
|
+
specify "should be accessable as a String to a case statement" do
|
10
|
+
("123" === NumericalString.new("123")).should == true
|
11
|
+
("0987" === NumericalString.new("0987")).should == true
|
12
|
+
end
|
13
|
+
|
14
|
+
specify "should satisfy Ranges" do
|
15
|
+
(100..200).should === NumericalString.new("150")
|
16
|
+
(100..200).should === NumericalString.new("0150")
|
17
|
+
((100..200) === NumericalString.new("1000000")).should === false
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "should satify regular expressions" do
|
21
|
+
/^\d+$/.should === NumericalString.new("027316287")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
#
|
25
|
+
# case extension
|
26
|
+
# when US_NUMBER
|
27
|
+
# when (100..200)
|
28
|
+
# when _('12Z')
|
29
|
+
# when 123
|
30
|
+
# when "123"
|
31
|
+
# end
|
32
|
+
|
33
|
+
context "A PhoneNumber" do
|
34
|
+
specify "should have an ISN pattern-matching method" do
|
35
|
+
!! PhoneNumber.new("0115544332211").isn?.should == false
|
36
|
+
!! PhoneNumber.new("1*548").isn?.should === false
|
37
|
+
end
|
38
|
+
|
39
|
+
specify "should have a US local number pattern-matching method" do
|
40
|
+
!! PhoneNumber.new("18887776665555").local_number?.should == false
|
41
|
+
!! PhoneNumber.new("18887776665555").national_number?.should == true
|
42
|
+
|
43
|
+
!! PhoneNumber.new("8887776665555").local_number?.should == false
|
44
|
+
!! PhoneNumber.new("8887776665555").national_number?.should == true
|
45
|
+
|
46
|
+
!! PhoneNumber.new("4445555").local_number?.should == true
|
47
|
+
!! PhoneNumber.new("4445555").national_number?.should == false
|
48
|
+
end
|
49
|
+
|
50
|
+
specify "should convert from vanity numbers properly" do
|
51
|
+
PhoneNumber.from_vanity("1-800-FUDGEME").should == "18003834363"
|
52
|
+
end
|
53
|
+
end
|