rebase_attr 1.1.0 → 2.0.0
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/rebase_attr.rb +50 -48
- data/lib/rebase_attr/version.rb +1 -1
- data/rebase_attr.gemspec +2 -0
- data/spec/rebase_attr_spec.rb +105 -63
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea935085ce8abb358a0cf745bed76b3eafcd2d23
|
4
|
+
data.tar.gz: 70e69e3bb784845327ff3fa78223bcb9c7c3d0c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8742d2a06433dfb567b4464d6025bff600502d1eafe487040e9ddb9faf4734d952a35b9bf10d926aaf0278bcd043542fb85c7086e7d3428a6fbd1012ad279639
|
7
|
+
data.tar.gz: 2805a5159796f79fea91660ae8886a0bd5378bd7123cd4585f946be19ef21f599f7e4044c1979b549a88ccfcbf03ac48c4d1da7ae80781e28c85a0c11485e660
|
data/README.md
CHANGED
@@ -36,7 +36,7 @@ Example for an active record table with long IDs:
|
|
36
36
|
#
|
37
37
|
|
38
38
|
class Bill < ActiveRecord::Base
|
39
|
-
rebase_attr :id,
|
39
|
+
rebase_attr :id, to: 32, readable: true # digits and leters, without '0', 'o', '1' and 'l'
|
40
40
|
end
|
41
41
|
```
|
42
42
|
|
data/lib/rebase_attr.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "rebase_attr/version"
|
2
|
+
require "generate_method"
|
2
3
|
|
3
4
|
module RebaseAttr
|
4
5
|
READABLE_MAPPING = { '0' => 'x', '1' => 'y', 'l' => 'w', 'o' => 'z' }
|
@@ -9,66 +10,67 @@ module RebaseAttr
|
|
9
10
|
raise ArgumentError, "#rebase_attr does not accept a block, did you mean to use :convert?" if block_given?
|
10
11
|
raise ArgumentError, "#rebase_attr does not allow :readable option with bases higher than 32, #{to} given" if readable and to > 32
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
generate_singleton_methods do
|
14
|
+
attributes.each do |attr|
|
15
|
+
# encoders & decoders
|
16
|
+
define_method :"encode_#{attr}" do |decoded|
|
17
|
+
break nil if decoded.nil?
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
define_method :"encode_#{attr}" do |decoded|
|
26
|
-
self.class.send(:"encode_#{attr}", decoded)
|
27
|
-
end
|
19
|
+
result = decoded
|
20
|
+
raise TypeError, "decoded value must implement #to_i, #{result.inspect} given" unless result.respond_to?(:to_i)
|
21
|
+
result = result.to_i(from || 10) if result.is_a?(String)
|
22
|
+
result = result.to_s(to)
|
23
|
+
READABLE_MAPPING.each { |s, d| result.gsub!(/#{s}/i, d) } if readable # gsub! to conserve memory
|
24
|
+
result = convert.respond_to?(:call) ? convert.call(result) : result.public_send(convert) if convert
|
25
|
+
result
|
26
|
+
end
|
28
27
|
|
29
|
-
|
30
|
-
|
28
|
+
define_method :"decode_#{attr}" do |encoded|
|
29
|
+
break nil if encoded.nil?
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
result = encoded
|
32
|
+
if deconvert
|
33
|
+
begin
|
34
|
+
result = result.clone # deconvert to not modify outside variable
|
35
|
+
rescue TypeError # can't clone, immutable
|
36
|
+
end
|
37
|
+
result = deconvert.respond_to?(:call) ? deconvert.call(result) : result.public_send(deconvert)
|
37
38
|
end
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
raise TypeError, "encoded value must implement #to_i, #{result.inspect} given" unless result.respond_to?(:to_i)
|
40
|
+
if readable
|
41
|
+
begin
|
42
|
+
result = result.clone # not modifying outside variable
|
43
|
+
rescue TypeError # can't clone, immutable
|
44
|
+
end
|
45
|
+
READABLE_MAPPING.each { |s, d| result.gsub!(/#{d}/i, s) } # gsub! to conserve memory
|
45
46
|
end
|
46
|
-
|
47
|
+
result = result.to_i(to)
|
48
|
+
result = result.to_s(from) if from
|
49
|
+
result
|
47
50
|
end
|
48
|
-
result = result.to_i(to)
|
49
|
-
result = result.to_s(from) if from
|
50
|
-
result
|
51
|
-
end
|
52
|
-
define_method :"decode_#{attr}" do |encoded|
|
53
|
-
self.class.send(:"decode_#{attr}", encoded)
|
54
51
|
end
|
52
|
+
end
|
55
53
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
54
|
+
generate_methods do
|
55
|
+
attributes.each do |attr|
|
56
|
+
# encoders & decoders
|
57
|
+
define_method :"encode_#{attr}" do |decoded|
|
58
|
+
self.class.send(:"encode_#{attr}", decoded)
|
59
|
+
end
|
60
|
+
define_method :"decode_#{attr}" do |encoded|
|
61
|
+
self.class.send(:"decode_#{attr}", encoded)
|
63
62
|
end
|
64
63
|
end
|
64
|
+
end
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
generate_methods(overrider: :rebase) do
|
67
|
+
attributes.each do |attr|
|
68
|
+
# readers & writers
|
69
|
+
define_method attr do
|
70
|
+
send(:"encode_#{attr}", respond_to?(:"#{attr}_without_rebase") ? send(:"#{attr}_without_rebase") : super())
|
71
|
+
end
|
70
72
|
define_method :"#{attr}=" do |encoded|
|
71
|
-
send(:"#{attr}_without_rebase=", send(:"decode_#{attr}", encoded))
|
73
|
+
respond_to?(:"#{attr}_without_rebase=") ? send(:"#{attr}_without_rebase=", send(:"decode_#{attr}", encoded)) : super(send(:"decode_#{attr}", encoded))
|
72
74
|
end
|
73
75
|
end
|
74
76
|
end
|
data/lib/rebase_attr/version.rb
CHANGED
data/rebase_attr.gemspec
CHANGED
@@ -18,6 +18,8 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
spec.add_runtime_dependency "generate_method", "~> 1.0"
|
22
|
+
|
21
23
|
spec.add_development_dependency "bundler", "~> 1.7"
|
22
24
|
spec.add_development_dependency "rspec", "~> 3.1"
|
23
25
|
spec.add_development_dependency "rspec-its", "~> 1.0"
|
data/spec/rebase_attr_spec.rb
CHANGED
@@ -1,17 +1,49 @@
|
|
1
1
|
require 'rebase_attr'
|
2
2
|
|
3
|
-
class
|
3
|
+
class RebaseWithAccessorTestBase
|
4
4
|
attr_accessor :x
|
5
5
|
end
|
6
6
|
|
7
|
+
class RebaseWithoutAccessorTestBase
|
8
|
+
def method_missing(method, *args, &block)
|
9
|
+
case method
|
10
|
+
when :x
|
11
|
+
@x
|
12
|
+
when :x=
|
13
|
+
@x = args.first
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
7
20
|
# This converts options to local varaibels so they can be used inside the Class.new { }
|
8
21
|
def rebase_class(**options, &block)
|
9
|
-
Class.new(
|
22
|
+
Class.new(RebaseWithAccessorTestBase) { rebase_attr(:x, **options, &block) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def rebase_classes(options_proc, &block)
|
26
|
+
context "with accessor" do
|
27
|
+
let(:klass) do
|
28
|
+
options = instance_eval(&options_proc) # converting to local variable before going inside the Class
|
29
|
+
Class.new(RebaseWithAccessorTestBase) { rebase_attr(:x, **options) }
|
30
|
+
end
|
31
|
+
@with_accessors = true
|
32
|
+
instance_eval(&block)
|
33
|
+
end
|
34
|
+
context "without accessor" do
|
35
|
+
let(:klass) do
|
36
|
+
options = instance_eval(&options_proc) # converting to local variable before going inside the Class
|
37
|
+
Class.new(RebaseWithoutAccessorTestBase) { rebase_attr(:x, **options) }
|
38
|
+
end
|
39
|
+
@with_accessors = false
|
40
|
+
instance_eval(&block)
|
41
|
+
end
|
10
42
|
end
|
11
43
|
|
12
44
|
describe RebaseAttr::Generator do
|
13
45
|
#requires: decoded, encoded
|
14
|
-
shared_examples_for "values" do
|
46
|
+
shared_examples_for "values" do |with_accessors|
|
15
47
|
subject(:instance) { klass.new }
|
16
48
|
|
17
49
|
describe "#encode" do
|
@@ -41,13 +73,13 @@ describe RebaseAttr::Generator do
|
|
41
73
|
|
42
74
|
describe "#without_rebase" do
|
43
75
|
context "when not nil" do
|
44
|
-
before { d = decoded; instance.instance_eval { @x = d } } # converting decoded to local variable so I can use it inside instance_eval
|
45
|
-
|
76
|
+
before { d = decoded; instance.instance_eval { @x = d } if with_accessors } # converting decoded to local variable so I can use it inside instance_eval
|
77
|
+
specify { expect(instance.x_without_rebase).to eq(decoded) if with_accessors }
|
46
78
|
end
|
47
79
|
|
48
80
|
context "when nil" do
|
49
|
-
before { instance.instance_eval { @x = nil } } # converting decoded to local variable so I can use it inside instance_eval
|
50
|
-
|
81
|
+
before { instance.instance_eval { @x = nil } if with_accessors } # converting decoded to local variable so I can use it inside instance_eval
|
82
|
+
specify { expect(instance.x_without_rebase).to be_nil if with_accessors }
|
51
83
|
end
|
52
84
|
end
|
53
85
|
|
@@ -65,13 +97,13 @@ describe RebaseAttr::Generator do
|
|
65
97
|
|
66
98
|
describe "#without_rebase=" do
|
67
99
|
context "when not nil" do
|
68
|
-
before { instance.x_without_rebase = decoded }
|
69
|
-
specify { expect(instance.instance_eval { @x }).to eq(decoded) }
|
100
|
+
before { instance.x_without_rebase = decoded if with_accessors }
|
101
|
+
specify { expect(instance.instance_eval { @x }).to eq(decoded) if with_accessors }
|
70
102
|
end
|
71
103
|
|
72
104
|
context "when nil" do
|
73
|
-
before { instance.x_without_rebase = nil }
|
74
|
-
specify { expect(instance.instance_eval { @x }).to be_nil }
|
105
|
+
before { instance.x_without_rebase = nil if with_accessors }
|
106
|
+
specify { expect(instance.instance_eval { @x }).to be_nil if with_accessors }
|
75
107
|
end
|
76
108
|
end
|
77
109
|
end
|
@@ -81,42 +113,47 @@ describe RebaseAttr::Generator do
|
|
81
113
|
shared_context "all except readable" do
|
82
114
|
context "without from" do
|
83
115
|
context "not converted" do
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
116
|
+
rebase_classes proc { { to: to } } do
|
117
|
+
let(:decoded) { decoded_default }
|
118
|
+
let(:encoded) { encoded_default }
|
119
|
+
it_behaves_like "values", @with_accessors
|
120
|
+
end
|
88
121
|
end
|
89
122
|
|
90
123
|
context "converted" do
|
91
124
|
context "named" do
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
125
|
+
rebase_classes proc { { to: to, convert: convert_name, deconvert: deconvert } } do
|
126
|
+
let(:decoded) { decoded_default }
|
127
|
+
let(:encoded) { encoded_convert }
|
128
|
+
it_behaves_like "values", @with_accessors
|
129
|
+
end
|
96
130
|
end
|
97
131
|
|
98
132
|
context "block" do
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
133
|
+
rebase_classes proc { { to: to, convert: convert_block, deconvert: deconvert } } do
|
134
|
+
let(:decoded) { decoded_default }
|
135
|
+
let(:encoded) { encoded_convert }
|
136
|
+
it_behaves_like "values", @with_accessors
|
137
|
+
end
|
103
138
|
end
|
104
139
|
end
|
105
140
|
end
|
106
141
|
|
107
142
|
context "from" do
|
108
143
|
context "not converted" do
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
144
|
+
rebase_classes proc { { from: from, to: to } } do
|
145
|
+
let(:decoded) { decoded_from }
|
146
|
+
let(:encoded) { encoded_default }
|
147
|
+
it_behaves_like "values", @with_accessors
|
148
|
+
end
|
113
149
|
end
|
114
150
|
|
115
151
|
context "converted" do
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
152
|
+
rebase_classes proc { { from: from, to: to, convert: convert_name, deconvert: deconvert } } do
|
153
|
+
let(:decoded) { decoded_from }
|
154
|
+
let(:encoded) { encoded_convert }
|
155
|
+
it_behaves_like "values", @with_accessors
|
156
|
+
end
|
120
157
|
end
|
121
158
|
end
|
122
159
|
end
|
@@ -129,33 +166,37 @@ describe RebaseAttr::Generator do
|
|
129
166
|
context "readable" do # 0 => x, 1 => y, l => w, o => z
|
130
167
|
context "without from" do
|
131
168
|
context "not converted" do
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
169
|
+
rebase_classes proc { { to: to, readable: true } } do
|
170
|
+
let(:decoded) { decoded_default }
|
171
|
+
let(:encoded) { encoded_readable }
|
172
|
+
it_behaves_like "values", @with_accessors
|
173
|
+
end
|
136
174
|
end
|
137
175
|
|
138
176
|
context "converted" do
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
177
|
+
rebase_classes proc { { to: to, readable: true, convert: convert_name, deconvert: deconvert } } do
|
178
|
+
let(:decoded) { decoded_default }
|
179
|
+
let(:encoded) { encoded_convert_readable }
|
180
|
+
it_behaves_like "values", @with_accessors
|
181
|
+
end
|
143
182
|
end
|
144
183
|
end
|
145
184
|
|
146
185
|
context "from" do
|
147
186
|
context "not converted" do
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
187
|
+
rebase_classes proc { { from: from, to: to, readable: true } } do
|
188
|
+
let(:decoded) { decoded_from }
|
189
|
+
let(:encoded) { encoded_readable }
|
190
|
+
it_behaves_like "values", @with_accessors
|
191
|
+
end
|
152
192
|
end
|
153
193
|
|
154
194
|
context "converted" do
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
195
|
+
rebase_classes proc { { from: from, to: to, readable: true, convert: convert_name, deconvert: deconvert } } do
|
196
|
+
let(:decoded) { decoded_from }
|
197
|
+
let(:encoded) { encoded_convert_readable }
|
198
|
+
it_behaves_like "values", @with_accessors
|
199
|
+
end
|
159
200
|
end
|
160
201
|
end
|
161
202
|
end
|
@@ -235,26 +276,27 @@ describe RebaseAttr::Generator do
|
|
235
276
|
specify { expect { rebase_class(to: 33, readable: true) }.to raise_error(ArgumentError, "#rebase_attr does not allow :readable option with bases higher than 32, 33 given") }
|
236
277
|
|
237
278
|
context "input" do
|
238
|
-
|
239
|
-
|
279
|
+
rebase_classes proc { { to: 16 } } do
|
280
|
+
let(:instance) { klass.new }
|
240
281
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
282
|
+
describe "#encode" do
|
283
|
+
specify { expect { klass.encode_x(:a) }.to raise_error(TypeError, "decoded value must implement #to_i, :a given") }
|
284
|
+
specify { expect { instance.encode_x(:a) }.to raise_error(TypeError, "decoded value must implement #to_i, :a given") }
|
285
|
+
end
|
245
286
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
287
|
+
describe "#decode" do
|
288
|
+
specify { expect { klass.decode_x(:a) }.to raise_error(TypeError, "encoded value must implement #to_i, :a given") }
|
289
|
+
specify { expect { instance.decode_x(:a) }.to raise_error(TypeError, "encoded value must implement #to_i, :a given") }
|
290
|
+
end
|
250
291
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
292
|
+
describe "reader" do
|
293
|
+
before { instance.instance_eval { @x = :a } }
|
294
|
+
specify { expect { instance.x }.to raise_error(TypeError, "decoded value must implement #to_i, :a given") }
|
295
|
+
end
|
255
296
|
|
256
|
-
|
257
|
-
|
297
|
+
describe "writer" do
|
298
|
+
specify { expect { instance.x = :a }.to raise_error(TypeError, "encoded value must implement #to_i, :a given") }
|
299
|
+
end
|
258
300
|
end
|
259
301
|
end
|
260
302
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rebase_attr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oded Niv
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: generate_method
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|