yab62 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
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
18
+ .DS_Store
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2-p180@yab62
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in yab62.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Teng Siong Ong
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.mkdn ADDED
@@ -0,0 +1,109 @@
1
+ YAB62 (Yet Another Base 62 Convertor)
2
+ =====================================
3
+
4
+ The idea of this gem is simple: I want to write a url shortener with base62. Ruby doesn't support it natively.
5
+ I checked out other gems: [radix62][1], [base62][2] and [alphadecimal][3].
6
+
7
+ They are all written in Ruby. Then, I have this idea to write this gem in C extension. Hence, YAB62 is born.
8
+
9
+ Btw, most of the tests are borrowed from [alphadecimal][3].
10
+
11
+ How to use
12
+ ==========
13
+
14
+ Install it with `gem install yab62`.
15
+
16
+ ```ruby
17
+ require 'yab62'
18
+
19
+ 1.encode62 # => "1"
20
+ "1".decode62 # => 1
21
+
22
+ # Or, you can do this:
23
+ YAB62.encode62(1) # => "1"
24
+ YAB62.decode62("1") # => 1
25
+ ```
26
+
27
+ Benchmark
28
+ =========
29
+
30
+ Check out the benchmark here:
31
+
32
+ ```ruby
33
+ # gem alphadecimal
34
+ time = Benchmark.measure do
35
+ 1_000_000.times do |i|
36
+ encode = i.alphadecimal
37
+ decode = encode.alphadecimal
38
+ raise "Assertion error!" unless i == decode
39
+ end
40
+ end
41
+
42
+ puts time # 17.060000 0.050000 17.110000 ( 17.507562)
43
+
44
+ # gem base62
45
+ time = Benchmark.measure do
46
+ 1_000_000.times do |i|
47
+ encode = i.base62_encode
48
+ decode = encode.base62_decode
49
+ raise "Assertion error!" unless i == decode
50
+ end
51
+ end
52
+
53
+ puts time # 9.600000 0.020000 9.620000 ( 9.802189)
54
+
55
+ # gem radix62
56
+ time = Benchmark.measure do
57
+ 1_000_000.times do |i|
58
+ encode = i.encode62
59
+ decode = encode.decode62
60
+ raise "Assertion error!" unless i == decode
61
+ end
62
+ end
63
+
64
+ puts time # 19.070000 0.040000 19.110000 ( 19.483596)
65
+
66
+ # gem yab62
67
+ time = Benchmark.measure do
68
+ 1_000_000.times do |i|
69
+ encode = i.encode62
70
+ decode = encode.decode62
71
+ raise "Assertion error!" unless i == decode
72
+ end
73
+ end
74
+
75
+ puts time # 0.550000 0.000000 0.550000 ( 0.605562)
76
+ ```
77
+
78
+ Check out the full script [here][4].
79
+
80
+ LICENSE
81
+ =======
82
+
83
+ (The MIT License)
84
+
85
+ Copyright (c) 2011 Teng Siong Ong
86
+
87
+ Permission is hereby granted, free of charge, to any person obtaining
88
+ a copy of this software and associated documentation files (the
89
+ 'Software'), to deal in the Software without restriction, including
90
+ without limitation the rights to use, copy, modify, merge, publish,
91
+ distribute, sublicense, and/or sell copies of the Software, and to
92
+ permit persons to whom the Software is furnished to do so, subject to
93
+ the following conditions:
94
+
95
+ The above copyright notice and this permission notice shall be
96
+ included in all copies or substantial portions of the Software.
97
+
98
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
99
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
100
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
101
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
102
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
103
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
104
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
105
+
106
+ [1]: https://github.com/k33l0r/radix62
107
+ [2]: https://github.com/jtzemp/base62
108
+ [3]: https://github.com/JackDanger/alphadecimal
109
+ [4]: https://gist.github.com/1369278
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ task :default => :test
5
+
6
+ require 'rake/testtask'
7
+ Rake::TestTask.new(:test) do |test|
8
+ test.libs << '.'
9
+ test.pattern = 'test/test_*.rb'
10
+ test.verbose = true
11
+ end
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile('yab62/yab62')
data/ext/yab62/yab62.c ADDED
@@ -0,0 +1,119 @@
1
+ #include <ruby.h>
2
+
3
+ /*
4
+ * base62.c
5
+ *
6
+ * Created by Jason Hullinger on 5/27/10.
7
+ *
8
+ * Modified by Teng Siong Ong on 11/15/2011.
9
+ */
10
+ #include <ctype.h>
11
+ #include <math.h>
12
+ #include <stdlib.h>
13
+ #include <string.h>
14
+
15
+ static const char base62_vals[] = "0123456789"
16
+ "abcdefghijklmnopqrstuvwxyz"
17
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
18
+
19
+ static const int base62_index[] = {
20
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
21
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
22
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
23
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
24
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0, 0,
25
+ 0, 0, 0, 0, 0, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
26
+ 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
27
+ 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0, 0, 0, 0, 0,
28
+ 0, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
29
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
30
+ 0x21, 0x22, 0x23,
31
+ };
32
+
33
+ void
34
+ strreverse_inplace (char *str)
35
+ {
36
+ char c;
37
+ u_int64_t half;
38
+ u_int64_t len;
39
+ u_int64_t i;
40
+
41
+ len = strlen(str);
42
+ half = len >> 1;
43
+ for (i = 0; i < half; i++) {
44
+ c = str[i];
45
+ str[i] = str[len - i - 1];
46
+ str[len - i - 1] = c;
47
+ }
48
+ }
49
+
50
+ int
51
+ base62_encode(u_int64_t val, char *str, size_t len)
52
+ {
53
+ u_int64_t i = 0;
54
+ u_int64_t v;
55
+
56
+ do {
57
+ if (i + 1 >= len)
58
+ return 0;
59
+ v = val % 62;
60
+ str[i++] = base62_vals[v];
61
+ val = (val - v) / 62;
62
+ } while (val > 0);
63
+ str[i] = '\0';
64
+ strreverse_inplace(str);
65
+
66
+ return 1;
67
+ }
68
+
69
+ u_int64_t
70
+ base62_decode (const char *str)
71
+ {
72
+ u_int64_t val = 0;
73
+ char c;
74
+ u_int64_t len;
75
+ u_int64_t i;
76
+
77
+ len = strlen(str);
78
+ for (i = 0; i < len; i++) {
79
+ c = str[i];
80
+ if (!isalnum(c)) {
81
+ rb_raise(rb_eArgError, "Input is not alphanumeric.");
82
+ }
83
+ val += base62_index[c] * pow(62, len - i - 1);
84
+ }
85
+
86
+ return val;
87
+ }
88
+
89
+ /* Ruby code starts here */
90
+
91
+ static VALUE alphadecimal_base62_encode(VALUE self, VALUE arg) {
92
+ long val = NUM2LONG(arg);
93
+ if (val < 0)
94
+ rb_raise(rb_eRangeError, "Number must be greater than or equal to 0");
95
+
96
+ char str[12];
97
+ base62_encode(val, str, 12);
98
+ return rb_str_new2(str);
99
+ }
100
+
101
+ static VALUE alphadecimal_base62_decode(VALUE self, VALUE arg) {
102
+ char* str = StringValuePtr(arg);
103
+ long val = base62_decode(str);
104
+ return ULL2NUM(val);
105
+ }
106
+
107
+ /* ruby calls this to load the extension */
108
+ void Init_yab62(void) {
109
+ // Create a Ruby module.
110
+ VALUE base62Module = rb_define_module("YAB62");
111
+
112
+ // Add a module method.
113
+ int arg_count = 1;
114
+ rb_define_singleton_method(base62Module, "encode62", alphadecimal_base62_encode, arg_count);
115
+
116
+ // Add a module method.
117
+ arg_count = 1;
118
+ rb_define_singleton_method(base62Module, "decode62", alphadecimal_base62_decode, arg_count);
119
+ }
data/lib/yab62.rb ADDED
@@ -0,0 +1,14 @@
1
+ require "yab62/version"
2
+ require "yab62/yab62"
3
+
4
+ class Integer
5
+ def encode62
6
+ YAB62.encode62(self)
7
+ end
8
+ end
9
+
10
+ class String
11
+ def decode62
12
+ YAB62.decode62(self)
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module YAB62
2
+ VERSION = "1.0.1"
3
+ end
@@ -0,0 +1,45 @@
1
+ # coding: utf-8
2
+
3
+ require 'test/unit'
4
+ require File.dirname(__FILE__) + "/../lib/yab62"
5
+
6
+ class TestYAB62 < Test::Unit::TestCase
7
+
8
+ include YAB62
9
+
10
+ def test_fixnum_becomes_string
11
+ assert_kind_of String, 45.encode62
12
+ end
13
+
14
+ def test_bignum_becomes_string
15
+ assert_kind_of String, 231087934571049032.encode62
16
+ end
17
+
18
+ def test_string_becomes_bignum
19
+ assert_kind_of Bignum, 'aHealk43JZy'.decode62
20
+ end
21
+
22
+ def test_string_becomes_fixnum
23
+ assert_kind_of Fixnum, 'j'.decode62
24
+ end
25
+
26
+
27
+ def test_edge_62_to_the_0_convertions_should_be_valid
28
+ (0...62).each do |i|
29
+ encode = i.encode62
30
+ decode = encode.decode62
31
+ assert_equal i, decode, "integer #{i.inspect} was encoded as #{encode.inspect} and was decoded to #{decode.inspect}"
32
+ end
33
+ end
34
+
35
+ def test_edge_62_to_the_n_convertions_should_be_valid
36
+ (0...3).each do |p|
37
+ n = 62 ** p
38
+ (0...62).each do |i|
39
+ encode = (i+n).encode62
40
+ decode = encode.decode62
41
+ assert_equal i+n, decode, "interger #{i+n} was encoded as #{encode} and was decoded to #{decode}"
42
+ end
43
+ end
44
+ end
45
+ end
data/yab62.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/yab62/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Teng Siong Ong"]
6
+ gem.email = ["siong1987@gmail.com"]
7
+ gem.description = %q{Yet another Base62 convertor}
8
+ gem.summary = %q{What do you expect? This is yet another Base62 convertor written in C extension.}
9
+ gem.homepage = "https://github.com/siong1987/yab62"
10
+ gem.extensions = ['ext/yab62/extconf.rb']
11
+
12
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ gem.name = "yab62"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = YAB62::VERSION
18
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yab62
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Teng Siong Ong
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-16 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: Yet another Base62 convertor
15
+ email:
16
+ - siong1987@gmail.com
17
+ executables: []
18
+ extensions:
19
+ - ext/yab62/extconf.rb
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - .rvmrc
24
+ - Gemfile
25
+ - LICENSE
26
+ - README.mkdn
27
+ - Rakefile
28
+ - ext/yab62/extconf.rb
29
+ - ext/yab62/yab62.c
30
+ - lib/yab62.rb
31
+ - lib/yab62/version.rb
32
+ - test/test_yab62.rb
33
+ - yab62.gemspec
34
+ homepage: https://github.com/siong1987/yab62
35
+ licenses: []
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubyforge_project:
54
+ rubygems_version: 1.8.10
55
+ signing_key:
56
+ specification_version: 3
57
+ summary: What do you expect? This is yet another Base62 convertor written in C extension.
58
+ test_files:
59
+ - test/test_yab62.rb