smstools 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4180ff46eb40f9d709cf9895d1dc493aeec4203c
4
+ data.tar.gz: cba4fd705516f2418dfae93ce3732231e30faba5
5
+ SHA512:
6
+ metadata.gz: b3b26b73c00f2acbb9e107ecc24738b97a713a3579c685339226b9ba369c0d2080ff7b40357a472c0dc9ebe41bca0f8ed38e28cd132242ce7ed3e514a78d69c3
7
+ data.tar.gz: 9b7a0e6a64fdaec4f8f05130dc3b4ac735f2848fddfd1bbd8d274ec2b6e9781fcdb993ef121357e77f6b4c486508a067e6480516a72fd33d7c28007397f0fde5
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,3 @@
1
+ ## 0.1.1 (17 January 2014)
2
+
3
+ * Initial release.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in smstools.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Dimitar Dimitrov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,71 @@
1
+ # Sms Tools
2
+
3
+ A small collection of useful Ruby and JavaScript classes implementing often
4
+ needed functionality for dealing with SMS messages.
5
+
6
+ The gem is also a Rails engine and using it in your Rails app will allow you
7
+ to also use the JavaScript classes via the asset pipeline.
8
+
9
+ ## Features
10
+
11
+ The following features are available on both the server side and the client
12
+ side:
13
+
14
+ - Detection of the most optimal encoding for sending an SMS message (GSM 7-bit
15
+ or Unicode).
16
+ - Correctly determining the message's length according to the most optimal
17
+ encoding.
18
+ - Concatenation detection and concatenated message parts counting.
19
+
20
+ And more.
21
+
22
+ ## Installation
23
+
24
+ Add this line to your application's Gemfile:
25
+
26
+ gem 'smstools'
27
+
28
+ And then execute:
29
+
30
+ $ bundle
31
+
32
+ Or install it yourself as:
33
+
34
+ $ gem install smstools
35
+
36
+ ## Usage
37
+
38
+ The gem consists of both server-side (Ruby) and client-side classes. You can
39
+ use either one.
40
+
41
+ ### Server-side code
42
+
43
+ If you use the gem in Rails or via Bundler, just use the appropriate class,
44
+ such as `SmsTools::EncodingDetection` or `SmsTools::GsmEncoding`.
45
+
46
+ #### `EncodingDetection`
47
+ #### `GsmEncoding`
48
+
49
+ ### Client-side code
50
+
51
+ If you're using the gem in Rails 3.x or newer, you can just add the following
52
+ to your `application.js` file to gain access to the JavaScript classes:
53
+
54
+ #= require 'sms_tools/all'
55
+
56
+ Or require only the files you need:
57
+
58
+ #= require 'sms_tools/message'
59
+
60
+ Note that this assumes you're using the asset pipeline. You need to have a
61
+ CoffeeScript preprocessor set up.
62
+
63
+ ## Contributing
64
+
65
+ 1. [Fork the repo](http://github.com/mitio/smstools/fork)
66
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
67
+ 3. Make your changes and provide tests for them
68
+ 4. Make sure all tests pass (run them with `bundle exec rake test`)
69
+ 5. Commit your changes (`git commit -am 'Add some feature'`)
70
+ 6. Push to the branch (`git push origin my-new-feature`)
71
+ 7. Send a pull request.
@@ -0,0 +1,11 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ task :test do
4
+ test_files = Dir[File.expand_path('../spec/**/*_spec.rb', __FILE__)]
5
+ command = "ruby -Ispec #{test_files.join ' '}"
6
+
7
+ puts "Running #{command}"
8
+ system command
9
+ end
10
+
11
+ task default: :test
@@ -0,0 +1 @@
1
+ #= require_tree .
@@ -0,0 +1,58 @@
1
+ window.SmsTools ?= {}
2
+
3
+ class SmsTools.Message
4
+ maxLengthForEncoding:
5
+ gsm:
6
+ normal: 160
7
+ concatenated: 153
8
+ unicode:
9
+ normal: 70
10
+ concatenated: 67
11
+
12
+ doubleByteCharsInGsmEncoding:
13
+ '^': true
14
+ '{': true
15
+ '}': true
16
+ '[': true
17
+ '~': true
18
+ ']': true
19
+ '|': true
20
+ '€': true
21
+ '\\': true
22
+
23
+ gsmEncodingPattern: /^[0-9a-zA-Z@Δ¡¿£_!Φ"¥Γ#èΛ¤éΩ%ùΠ&ìΨòΣçΘΞ:Ø;ÄäøÆ,<Ööæ=ÑñÅß>Üüåɧà€~ \$\.\-\+\(\)\*\\\/\?\|\^\}\{\[\]\'\r\n]*$/
24
+
25
+ constructor: (@text) ->
26
+ @text = @text.replace /\r\n?/g, "\n"
27
+ @encoding = @_encoding()
28
+ @length = @_length()
29
+ @concatenatedPartsCount = @_concatenatedPartsCount()
30
+
31
+ maxLengthFor: (concatenatedPartsCount) ->
32
+ messageType = if concatenatedPartsCount > 1 then 'concatenated' else 'normal'
33
+
34
+ concatenatedPartsCount * @maxLengthForEncoding[@encoding][messageType]
35
+
36
+ _encoding: ->
37
+ if @gsmEncodingPattern.test(@text) then 'gsm' else 'unicode'
38
+
39
+ _concatenatedPartsCount: ->
40
+ encoding = @encoding
41
+ length = @length
42
+
43
+ if length <= @maxLengthForEncoding[encoding].normal
44
+ 1
45
+ else
46
+ parseInt Math.ceil(length / @maxLengthForEncoding[encoding].concatenated), 10
47
+
48
+ # Returns the number of symbols, which the given text will take up in an SMS
49
+ # message, taking into account any double-space symbols in the GSM 03.38
50
+ # encoding.
51
+ _length: ->
52
+ length = @text.length
53
+
54
+ if @encoding == 'gsm'
55
+ for char in @text
56
+ length += 1 if @doubleByteCharsInGsmEncoding[char]
57
+
58
+ length
@@ -0,0 +1,7 @@
1
+ require 'sms_tools/version'
2
+ require 'sms_tools/encoding_detection'
3
+ require 'sms_tools/gsm_encoding'
4
+
5
+ if defined?(::Rails) and ::Rails.version >= '3.1'
6
+ require 'sms_tools/rails/engine'
7
+ end
@@ -0,0 +1,62 @@
1
+ require 'sms_tools/gsm_encoding'
2
+
3
+ module SmsTools
4
+ class EncodingDetection
5
+ MAX_LENGTH_FOR_ENCODING = {
6
+ gsm: {
7
+ normal: 160,
8
+ concatenated: 153,
9
+ },
10
+ unicode: {
11
+ normal: 70,
12
+ concatenated: 67,
13
+ },
14
+ }.freeze
15
+
16
+ attr :text
17
+
18
+ def initialize(text)
19
+ @text = text
20
+ end
21
+
22
+ def encoding
23
+ @encoding ||= GsmEncoding.valid?(text) ? :gsm : :unicode
24
+ end
25
+
26
+ def gsm?
27
+ encoding == :gsm
28
+ end
29
+
30
+ def unicode?
31
+ encoding == :unicode
32
+ end
33
+
34
+ def concatenated?
35
+ concatenated_parts > 1
36
+ end
37
+
38
+ def concatenated_parts
39
+ if length <= MAX_LENGTH_FOR_ENCODING[encoding][:normal]
40
+ 1
41
+ else
42
+ (length.to_f / MAX_LENGTH_FOR_ENCODING[encoding][:concatenated]).ceil
43
+ end
44
+ end
45
+
46
+ def maximum_length_for(concatenated_parts)
47
+ message_type = concatenated_parts > 1 ? :concatenated : :normal
48
+
49
+ concatenated_parts * MAX_LENGTH_FOR_ENCODING[encoding][message_type]
50
+ end
51
+
52
+ # Returns the number of symbols, which the given text will take up in an SMS
53
+ # message, taking into account any double-space symbols in the GSM 03.38
54
+ # encoding.
55
+ def length
56
+ length = text.length
57
+ length += text.chars.count { |char| GsmEncoding.double_byte?(char) } if gsm?
58
+
59
+ length
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,195 @@
1
+ module SmsTools
2
+ # UTF-8 to GSM-7 (GSM 03.38) mapping. Based on code from:
3
+ # https://github.com/threez/smspromote/blob/master/lib/smspromote/encoding.rb
4
+ module GsmEncoding
5
+ extend self
6
+
7
+ UTF8_TO_GSM_BASE_TABLE = {
8
+ 0x0040 => "\x00", # COMMERCIAL AT
9
+ 0x00A3 => "\x01", # POUND SIGN
10
+ 0x0024 => "\x02", # DOLLAR SIGN
11
+ 0x00A5 => "\x03", # YEN SIGN
12
+ 0x00E8 => "\x04", # LATIN SMALL LETTER E WITH GRAVE
13
+ 0x00E9 => "\x05", # LATIN SMALL LETTER E WITH ACUTE
14
+ 0x00F9 => "\x06", # LATIN SMALL LETTER U WITH GRAVE
15
+ 0x00EC => "\x07", # LATIN SMALL LETTER I WITH GRAVE
16
+ 0x00F2 => "\x08", # LATIN SMALL LETTER O WITH GRAVE
17
+ 0x00E7 => "\x09", # LATIN SMALL LETTER C WITH CEDILLA
18
+ 0x000A => "\x0A", # LINE FEED
19
+ 0x00D8 => "\x0B", # LATIN CAPITAL LETTER O WITH STROKE
20
+ 0x00F8 => "\x0C", # LATIN SMALL LETTER O WITH STROKE
21
+ 0x000D => "\x0D", # CARRIAGE RETURN
22
+ 0x00C5 => "\x0E", # LATIN CAPITAL LETTER A WITH RING ABOVE
23
+ 0x00E5 => "\x0F", # LATIN SMALL LETTER A WITH RING ABOVE
24
+ 0x0394 => "\x10", # GREEK CAPITAL LETTER DELTA
25
+ 0x005F => "\x11", # LOW LINE
26
+ 0x03A6 => "\x12", # GREEK CAPITAL LETTER PHI
27
+ 0x0393 => "\x13", # GREEK CAPITAL LETTER GAMMA
28
+ 0x039B => "\x14", # GREEK CAPITAL LETTER LAMDA
29
+ 0x03A9 => "\x15", # GREEK CAPITAL LETTER OMEGA
30
+ 0x03A0 => "\x16", # GREEK CAPITAL LETTER PI
31
+ 0x03A8 => "\x17", # GREEK CAPITAL LETTER PSI
32
+ 0x03A3 => "\x18", # GREEK CAPITAL LETTER SIGMA
33
+ 0x0398 => "\x19", # GREEK CAPITAL LETTER THETA
34
+ 0x039E => "\x1A", # GREEK CAPITAL LETTER XI
35
+ 0x00A0 => "\x1B", # ESCAPE TO EXTENSION TABLE
36
+ 0x00C6 => "\x1C", # LATIN CAPITAL LETTER AE
37
+ 0x00E6 => "\x1D", # LATIN SMALL LETTER AE
38
+ 0x00DF => "\x1E", # LATIN SMALL LETTER SHARP S (German)
39
+ 0x00C9 => "\x1F", # LATIN CAPITAL LETTER E WITH ACUTE
40
+ 0x0020 => "\x20", # SPACE
41
+ 0x0021 => "\x21", # EXCLAMATION MARK
42
+ 0x0022 => "\x22", # QUOTATION MARK
43
+ 0x0023 => "\x23", # NUMBER SIGN
44
+ 0x00A4 => "\x24", # CURRENCY SIGN
45
+ 0x0025 => "\x25", # PERCENT SIGN
46
+ 0x0026 => "\x26", # AMPERSAND
47
+ 0x0027 => "\x27", # APOSTROPHE
48
+ 0x0028 => "\x28", # LEFT PARENTHESIS
49
+ 0x0029 => "\x29", # RIGHT PARENTHESIS
50
+ 0x002A => "\x2A", # ASTERISK
51
+ 0x002B => "\x2B", # PLUS SIGN
52
+ 0x002C => "\x2C", # COMMA
53
+ 0x002D => "\x2D", # HYPHEN-MINUS
54
+ 0x002E => "\x2E", # FULL STOP
55
+ 0x002F => "\x2F", # SOLIDUS
56
+ 0x0030 => "\x30", # DIGIT ZERO
57
+ 0x0031 => "\x31", # DIGIT ONE
58
+ 0x0032 => "\x32", # DIGIT TWO
59
+ 0x0033 => "\x33", # DIGIT THREE
60
+ 0x0034 => "\x34", # DIGIT FOUR
61
+ 0x0035 => "\x35", # DIGIT FIVE
62
+ 0x0036 => "\x36", # DIGIT SIX
63
+ 0x0037 => "\x37", # DIGIT SEVEN
64
+ 0x0038 => "\x38", # DIGIT EIGHT
65
+ 0x0039 => "\x39", # DIGIT NINE
66
+ 0x003A => "\x3A", # COLON
67
+ 0x003B => "\x3B", # SEMICOLON
68
+ 0x003C => "\x3C", # LESS-THAN SIGN
69
+ 0x003D => "\x3D", # EQUALS SIGN
70
+ 0x003E => "\x3E", # GREATER-THAN SIGN
71
+ 0x003F => "\x3F", # QUESTION MARK
72
+ 0x00A1 => "\x40", # INVERTED EXCLAMATION MARK
73
+ 0x0041 => "\x41", # LATIN CAPITAL LETTER A
74
+ 0x0042 => "\x42", # LATIN CAPITAL LETTER B
75
+ 0x0043 => "\x43", # LATIN CAPITAL LETTER C
76
+ 0x0044 => "\x44", # LATIN CAPITAL LETTER D
77
+ 0x0045 => "\x45", # LATIN CAPITAL LETTER E
78
+ 0x0046 => "\x46", # LATIN CAPITAL LETTER F
79
+ 0x0047 => "\x47", # LATIN CAPITAL LETTER G
80
+ 0x0048 => "\x48", # LATIN CAPITAL LETTER H
81
+ 0x0049 => "\x49", # LATIN CAPITAL LETTER I
82
+ 0x004A => "\x4A", # LATIN CAPITAL LETTER J
83
+ 0x004B => "\x4B", # LATIN CAPITAL LETTER K
84
+ 0x004C => "\x4C", # LATIN CAPITAL LETTER L
85
+ 0x004D => "\x4D", # LATIN CAPITAL LETTER M
86
+ 0x004E => "\x4E", # LATIN CAPITAL LETTER N
87
+ 0x004F => "\x4F", # LATIN CAPITAL LETTER O
88
+ 0x0050 => "\x50", # LATIN CAPITAL LETTER P
89
+ 0x0051 => "\x51", # LATIN CAPITAL LETTER Q
90
+ 0x0052 => "\x52", # LATIN CAPITAL LETTER R
91
+ 0x0053 => "\x53", # LATIN CAPITAL LETTER S
92
+ 0x0054 => "\x54", # LATIN CAPITAL LETTER T
93
+ 0x0055 => "\x55", # LATIN CAPITAL LETTER U
94
+ 0x0056 => "\x56", # LATIN CAPITAL LETTER V
95
+ 0x0057 => "\x57", # LATIN CAPITAL LETTER W
96
+ 0x0058 => "\x58", # LATIN CAPITAL LETTER X
97
+ 0x0059 => "\x59", # LATIN CAPITAL LETTER Y
98
+ 0x005A => "\x5A", # LATIN CAPITAL LETTER Z
99
+ 0x00C4 => "\x5B", # LATIN CAPITAL LETTER A WITH DIAERESIS
100
+ 0x00D6 => "\x5C", # LATIN CAPITAL LETTER O WITH DIAERESIS
101
+ 0x00D1 => "\x5D", # LATIN CAPITAL LETTER N WITH TILDE
102
+ 0x00DC => "\x5E", # LATIN CAPITAL LETTER U WITH DIAERESIS
103
+ 0x00A7 => "\x5F", # SECTION SIGN
104
+ 0x00BF => "\x60", # INVERTED QUESTION MARK
105
+ 0x0061 => "\x61", # LATIN SMALL LETTER A
106
+ 0x0062 => "\x62", # LATIN SMALL LETTER B
107
+ 0x0063 => "\x63", # LATIN SMALL LETTER C
108
+ 0x0064 => "\x64", # LATIN SMALL LETTER D
109
+ 0x0065 => "\x65", # LATIN SMALL LETTER E
110
+ 0x0066 => "\x66", # LATIN SMALL LETTER F
111
+ 0x0067 => "\x67", # LATIN SMALL LETTER G
112
+ 0x0068 => "\x68", # LATIN SMALL LETTER H
113
+ 0x0069 => "\x69", # LATIN SMALL LETTER I
114
+ 0x006A => "\x6A", # LATIN SMALL LETTER J
115
+ 0x006B => "\x6B", # LATIN SMALL LETTER K
116
+ 0x006C => "\x6C", # LATIN SMALL LETTER L
117
+ 0x006D => "\x6D", # LATIN SMALL LETTER M
118
+ 0x006E => "\x6E", # LATIN SMALL LETTER N
119
+ 0x006F => "\x6F", # LATIN SMALL LETTER O
120
+ 0x0070 => "\x70", # LATIN SMALL LETTER P
121
+ 0x0071 => "\x71", # LATIN SMALL LETTER Q
122
+ 0x0072 => "\x72", # LATIN SMALL LETTER R
123
+ 0x0073 => "\x73", # LATIN SMALL LETTER S
124
+ 0x0074 => "\x74", # LATIN SMALL LETTER T
125
+ 0x0075 => "\x75", # LATIN SMALL LETTER U
126
+ 0x0076 => "\x76", # LATIN SMALL LETTER V
127
+ 0x0077 => "\x77", # LATIN SMALL LETTER W
128
+ 0x0078 => "\x78", # LATIN SMALL LETTER X
129
+ 0x0079 => "\x79", # LATIN SMALL LETTER Y
130
+ 0x007A => "\x7A", # LATIN SMALL LETTER Z
131
+ 0x00E4 => "\x7B", # LATIN SMALL LETTER A WITH DIAERESIS
132
+ 0x00F6 => "\x7C", # LATIN SMALL LETTER O WITH DIAERESIS
133
+ 0x00F1 => "\x7D", # LATIN SMALL LETTER N WITH TILDE
134
+ 0x00FC => "\x7E", # LATIN SMALL LETTER U WITH DIAERESIS
135
+ 0x00E0 => "\x7F", # LATIN SMALL LETTER A WITH GRAVE
136
+ }.freeze
137
+
138
+ UTF8_TO_GSM_EXTENSION_TABLE = {
139
+ 0x000C => "\x1B\x0A", # FORM FEED
140
+ 0x005E => "\x1B\x14", # CIRCUMFLEX ACCENT
141
+ 0x007B => "\x1B\x28", # LEFT CURLY BRACKET
142
+ 0x007D => "\x1B\x29", # RIGHT CURLY BRACKET
143
+ 0x005C => "\x1B\x2F", # REVERSE SOLIDUS
144
+ 0x005B => "\x1B\x3C", # LEFT SQUARE BRACKET
145
+ 0x007E => "\x1B\x3D", # TILDE
146
+ 0x005D => "\x1B\x3E", # RIGHT SQUARE BRACKET
147
+ 0x007C => "\x1B\x40", # VERTICAL LINE
148
+ 0x20AC => "\x1B\x65" # EURO SIGN
149
+ }.freeze
150
+
151
+ UTF8_TO_GSM = UTF8_TO_GSM_BASE_TABLE.merge(UTF8_TO_GSM_EXTENSION_TABLE).freeze
152
+ GSM_TO_UTF8 = UTF8_TO_GSM.invert.freeze
153
+
154
+ def valid?(utf8_encoded_string)
155
+ utf8_encoded_string.unpack('U*').all? { |char| UTF8_TO_GSM[char] }
156
+ end
157
+
158
+ def double_byte?(char)
159
+ UTF8_TO_GSM_EXTENSION_TABLE[char.unpack('U').first]
160
+ end
161
+
162
+ def from_utf8(utf8_encoded_string)
163
+ gsm_encoded_string = ''
164
+
165
+ utf8_encoded_string.unpack('U*').each do |char|
166
+ if converted = UTF8_TO_GSM[char]
167
+ gsm_encoded_string << converted
168
+ else
169
+ raise "Unsupported symbol in GSM-7 encoding: 0x#{char.to_s(16).upcase}"
170
+ end
171
+ end
172
+
173
+ gsm_encoded_string
174
+ end
175
+
176
+ def to_utf8(gsm_encoded_string)
177
+ utf8_encoded_string = ''
178
+ escape = false
179
+ escape_code = "\e".freeze
180
+
181
+ gsm_encoded_string.each_char do |char|
182
+ if char == escape_code
183
+ escape = true
184
+ elsif escape
185
+ escape = false
186
+ utf8_encoded_string << [GSM_TO_UTF8[escape_code + char]].pack('U')
187
+ else
188
+ utf8_encoded_string << [GSM_TO_UTF8[char]].pack('U')
189
+ end
190
+ end
191
+
192
+ utf8_encoded_string
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,6 @@
1
+ module SmsTools
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module SmsTools
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1 @@
1
+ require 'sms_tools'
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sms_tools/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'smstools'
8
+ spec.version = SmsTools::VERSION
9
+ spec.authors = ['Dimitar Dimitrov']
10
+ spec.email = ['me@ddimitrov.name']
11
+ spec.summary = 'Small library of classes for common SMS-related functionality.'
12
+ spec.description = 'Features SMS text encoding detection, length counting, concatenation detection and more. Can be used with or without Rails. Requires Ruby 1.9 or newer.'
13
+ spec.homepage = 'https://github.com/mitio/smstools'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.5'
22
+ spec.add_development_dependency 'rake'
23
+ spec.add_development_dependency 'minitest'
24
+ spec.add_development_dependency 'minitest-ansi'
25
+ end
@@ -0,0 +1,153 @@
1
+ require 'spec_helper'
2
+ require 'sms_tools/encoding_detection'
3
+
4
+ describe SmsTools::EncodingDetection do
5
+ it "exposes the original text as a method" do
6
+ detection_for('foo').text.must_equal 'foo'
7
+ end
8
+
9
+ describe "encoding" do
10
+ it "defaults to GSM encoding for empty messages" do
11
+ detection_for('').encoding.must_equal :gsm
12
+ end
13
+
14
+ it "returns GSM as encoding for simple ASCII text" do
15
+ detection_for('foo bar baz').encoding.must_equal :gsm
16
+ end
17
+
18
+ it "returns GSM as encoding for special symbols defined in GSM 03.38" do
19
+ detection_for('09azAZ@Δ¡¿£_!Φ"¥Γ#èΛ¤éΩ%ùΠ&ìΨòΣçΘΞ:Ø;ÄäøÆ,<Ööæ=ÑñÅß>Üüåɧà€~').encoding.must_equal :gsm
20
+ end
21
+
22
+ it "returns GSM as encoding for puntucation and newline symbols" do
23
+ detection_for('Foo bar {} [baz]! Larodi $5. What else?').encoding.must_equal :gsm
24
+ detection_for("Spaces and newlines are GSM 03.38, too: \r\n").encoding.must_equal :gsm
25
+ end
26
+
27
+ it "returns Unicode when non-GSM Unicode symbols are used" do
28
+ detection_for('Foo bar лароди').encoding.must_equal :unicode
29
+ detection_for('∞').encoding.must_equal :unicode
30
+ end
31
+ end
32
+
33
+ describe "message length" do
34
+ it "computes the length of trivial ANSI-only messages correctly" do
35
+ detection_for('').length.must_equal 0
36
+ detection_for('larodi').length.must_equal 6
37
+ detection_for('a' * 180).length.must_equal 180
38
+ end
39
+
40
+ it "computes the length of non-trivial GSM encoded messages correctly" do
41
+ detection_for('GSM: 09azAZ@Δ¡¿£_!Φ"¥Γ#èΛ¤éΩ%ùΠ&ìΨòΣçΘΞ:Ø;ÄäøÆ,<Ööæ=ÑñÅß>Üüåɧà').length.must_equal 63
42
+ end
43
+
44
+ it "correctly counts the length of whitespace-only messages" do
45
+ detection_for(' ').length.must_equal 5
46
+ detection_for("\r\n ").length.must_equal 4
47
+ end
48
+
49
+ it "correctly counts the length of whitespace chars in GSM-encoded messages" do
50
+ detection_for('ΞØ ').length.must_equal 7
51
+ detection_for("ΞØ\r\n ").length.must_equal 6
52
+ end
53
+
54
+ it "counts double-space chars for GSM encoding" do
55
+ detection_for('^{}[~]|€\\').length.must_equal 18
56
+ detection_for('Σ: €').length.must_equal 5
57
+ end
58
+
59
+ it "computes the length of Unicode messages correctly" do
60
+ detection_for('кирилица').length.must_equal 8
61
+ detection_for('Я!').length.must_equal 2
62
+ detection_for("Уникод: ΞØ\r\n ").length.must_equal 14
63
+ detection_for('Ю' * 200).length.must_equal 200
64
+ end
65
+
66
+ it "doesn't count double-space chars for Unicode encoding" do
67
+ detection_for('Уникод: ^{}[~]|€\\').length.must_equal 17
68
+ detection_for('Уникод: Σ: €').length.must_equal 12
69
+ end
70
+ end
71
+
72
+ describe "concatenated message parts counting" do
73
+ def concatenated_parts_for(length: nil, encoding: nil, must_be: nil)
74
+ SmsTools::EncodingDetection.new('').stub :length, length do |detection|
75
+ detection.stub :encoding, encoding do |detection|
76
+ detection.concatenated_parts.must_equal must_be
77
+ end
78
+ end
79
+ end
80
+
81
+ it "counts parts for GSM-encoded messages" do
82
+ concatenated_parts_for length: 0, encoding: :gsm, must_be: 1
83
+ concatenated_parts_for length: 160, encoding: :gsm, must_be: 1
84
+ concatenated_parts_for length: 161, encoding: :gsm, must_be: 2
85
+ concatenated_parts_for length: 306, encoding: :gsm, must_be: 2
86
+ concatenated_parts_for length: 307, encoding: :gsm, must_be: 3
87
+ concatenated_parts_for length: 459, encoding: :gsm, must_be: 3
88
+ concatenated_parts_for length: 500, encoding: :gsm, must_be: 4
89
+ end
90
+
91
+ it "counts parts for Unicode messages" do
92
+ concatenated_parts_for length: 0, encoding: :unicode, must_be: 1
93
+ concatenated_parts_for length: 70, encoding: :unicode, must_be: 1
94
+ concatenated_parts_for length: 71, encoding: :unicode, must_be: 2
95
+ concatenated_parts_for length: 134, encoding: :unicode, must_be: 2
96
+ concatenated_parts_for length: 135, encoding: :unicode, must_be: 3
97
+ end
98
+
99
+ it "counts parts for actual GSM-encoded and Unicode messages" do
100
+ detection_for('').concatenated_parts.must_equal 1
101
+ detection_for('Я').concatenated_parts.must_equal 1
102
+ detection_for('Σ' * 160).concatenated_parts.must_equal 1
103
+ detection_for('Σ' * 159 + '~').concatenated_parts.must_equal 2
104
+ detection_for('Я' * 133 + '~').concatenated_parts.must_equal 2
105
+ end
106
+ end
107
+
108
+ describe "maximum length for particular number of concatenated messages" do
109
+ it "works for GSM-encoded messages" do
110
+ detection_for('x').maximum_length_for(1).must_equal 160
111
+ detection_for('x').maximum_length_for(2).must_equal 306
112
+ detection_for('x').maximum_length_for(3).must_equal 459
113
+ end
114
+
115
+ it "works for Unicode messages" do
116
+ detection_for('ю').maximum_length_for(1).must_equal 70
117
+ detection_for('ю').maximum_length_for(2).must_equal 134
118
+ detection_for('ю').maximum_length_for(3).must_equal 201
119
+ end
120
+ end
121
+
122
+ describe "predicates" do
123
+ it "returns true for gsm? and false for unicode? if the encoding is GSM" do
124
+ detection_for('').stub :encoding, :gsm do |detection|
125
+ detection.must_be :gsm?
126
+ detection.wont_be :unicode?
127
+ end
128
+ end
129
+
130
+ it "returns false for gsm? and true for unicode? if the encoding is Unicode" do
131
+ detection_for('').stub :encoding, :unicode do |detection|
132
+ detection.wont_be :gsm?
133
+ detection.must_be :unicode?
134
+ end
135
+ end
136
+
137
+ it "returns true for concatenated? if concatenated_parts > 1" do
138
+ detection_for('').stub :concatenated_parts, 7 do |detection|
139
+ detection.must_be :concatenated?
140
+ end
141
+ end
142
+
143
+ it "returns false for concatenated? if concatenated_parts is 1" do
144
+ detection_for('').stub :concatenated_parts, 1 do |detection|
145
+ detection.wont_be :concatenated?
146
+ end
147
+ end
148
+ end
149
+
150
+ def detection_for(text)
151
+ SmsTools::EncodingDetection.new text
152
+ end
153
+ end
@@ -0,0 +1,8 @@
1
+ lib = File.expand_path('../../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'minitest/spec'
5
+ require 'minitest/ansi'
6
+ require 'minitest/autorun'
7
+
8
+ MiniTest::ANSI.use!
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smstools
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dimitar Dimitrov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-ansi
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Features SMS text encoding detection, length counting, concatenation
70
+ detection and more. Can be used with or without Rails. Requires Ruby 1.9 or newer.
71
+ email:
72
+ - me@ddimitrov.name
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - CHANGELOG.md
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - lib/assets/javascripts/sms_tools/index.js.coffee
84
+ - lib/assets/javascripts/sms_tools/message.js.coffee
85
+ - lib/sms_tools.rb
86
+ - lib/sms_tools/encoding_detection.rb
87
+ - lib/sms_tools/gsm_encoding.rb
88
+ - lib/sms_tools/rails/engine.rb
89
+ - lib/sms_tools/version.rb
90
+ - lib/smstools.rb
91
+ - smstools.gemspec
92
+ - spec/sms_tools/encoding_detection_spec.rb
93
+ - spec/spec_helper.rb
94
+ homepage: https://github.com/mitio/smstools
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.2.0
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: Small library of classes for common SMS-related functionality.
118
+ test_files:
119
+ - spec/sms_tools/encoding_detection_spec.rb
120
+ - spec/spec_helper.rb