smstools 0.0.1

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.
@@ -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