adhearsion 0.7.6 → 0.7.7
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/.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
|