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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1c989126e78f373d7608f11824429b65974311bc
4
- data.tar.gz: 2859dd7b67c93645a72d0ad8f38ee128b9d72d29
3
+ metadata.gz: ea935085ce8abb358a0cf745bed76b3eafcd2d23
4
+ data.tar.gz: 70e69e3bb784845327ff3fa78223bcb9c7c3d0c1
5
5
  SHA512:
6
- metadata.gz: e812eced8377afca51ce32ee032411782b1aba3395df1b7480603011a2c6a3e988406d0d12eb6d3fad162afdab3c0353ab7c67e5256e1add033e540b8991afc3
7
- data.tar.gz: bc4df6f016698c5a4ec2c89c48eda5f243beb5c709a29f10d65331b80f344076c5e4bd7b523adf335bc44b40b39cb8a40a6d8834524a2adba2a4a537cbf383b4
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, base: 32, readable: true # only digits and leters, without '0', '1', 'i' and 'l'
39
+ rebase_attr :id, to: 32, readable: true # digits and leters, without '0', 'o', '1' and 'l'
40
40
  end
41
41
  ```
42
42
 
@@ -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
- attributes.each do |attr|
13
- # encoders & decoders
14
- define_singleton_method :"encode_#{attr}" do |decoded|
15
- break nil if decoded.nil?
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
- result = decoded
18
- raise TypeError, "decoded value must implement #to_i, #{result.inspect} given" unless result.respond_to?(:to_i)
19
- result = result.to_i(from || 10) if result.is_a?(String)
20
- result = result.to_s(to)
21
- READABLE_MAPPING.each { |s, d| result.gsub!(/#{s}/i, d) } if readable # gsub! to conserve memory
22
- result = convert.respond_to?(:call) ? convert.call(result) : result.public_send(convert) if convert
23
- result
24
- end
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
- define_singleton_method :"decode_#{attr}" do |encoded|
30
- break nil if encoded.nil?
28
+ define_method :"decode_#{attr}" do |encoded|
29
+ break nil if encoded.nil?
31
30
 
32
- result = encoded
33
- if deconvert
34
- begin
35
- result = result.clone # deconvert to not modify outside variable
36
- rescue TypeError # can't clone, immutable
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
- result = deconvert.respond_to?(:call) ? deconvert.call(result) : result.public_send(deconvert)
39
- end
40
- raise TypeError, "encoded value must implement #to_i, #{result.inspect} given" unless result.respond_to?(:to_i)
41
- if readable
42
- begin
43
- result = result.clone # not modifying outside variable
44
- rescue TypeError # can't clone, immutable
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
- READABLE_MAPPING.each { |s, d| result.gsub!(/#{d}/i, s) } # gsub! to conserve memory
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
- # readers & writers
57
- begin
58
- alias_method :"#{attr}_without_rebase", attr
59
- rescue NameError # reader does not exist
60
- else
61
- define_method attr do
62
- send(:"encode_#{attr}", send(:"#{attr}_without_rebase"))
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
- begin
67
- alias_method :"#{attr}_without_rebase=", :"#{attr}="
68
- rescue NameError # writer does not exist
69
- else
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
@@ -1,3 +1,3 @@
1
1
  module RebaseAttr
2
- VERSION = "1.1.0"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -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"
@@ -1,17 +1,49 @@
1
1
  require 'rebase_attr'
2
2
 
3
- class RebaseTestBase
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(RebaseTestBase) { rebase_attr(:x, **options, &block) }
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
- its(:x_without_rebase) { should == decoded }
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
- its(:x_without_rebase) { should be_nil }
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
- let(:klass) { rebase_class to: to }
85
- let(:decoded) { decoded_default }
86
- let(:encoded) { encoded_default }
87
- it_behaves_like "values"
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
- let(:klass) { rebase_class to: to, convert: convert_name, deconvert: deconvert }
93
- let(:decoded) { decoded_default }
94
- let(:encoded) { encoded_convert }
95
- it_behaves_like "values"
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
- let(:klass) { rebase_class to: to, convert: convert_block, deconvert: deconvert }
100
- let(:decoded) { decoded_default }
101
- let(:encoded) { encoded_convert }
102
- it_behaves_like "values"
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
- let(:klass) { rebase_class from: from, to: to }
110
- let(:decoded) { decoded_from }
111
- let(:encoded) { encoded_default }
112
- it_behaves_like "values"
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
- let(:klass) { rebase_class from: from, to: to, convert: convert_name, deconvert: deconvert }
117
- let(:decoded) { decoded_from }
118
- let(:encoded) { encoded_convert }
119
- it_behaves_like "values"
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
- let(:klass) { rebase_class to: to, readable: true }
133
- let(:decoded) { decoded_default }
134
- let(:encoded) { encoded_readable }
135
- it_behaves_like "values"
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
- let(:klass) { rebase_class to: to, readable: true, convert: convert_name, deconvert: deconvert }
140
- let(:decoded) { decoded_default }
141
- let(:encoded) { encoded_convert_readable }
142
- it_behaves_like "values"
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
- let(:klass) { rebase_class from: from, to: to, readable: true }
149
- let(:decoded) { decoded_from }
150
- let(:encoded) { encoded_readable }
151
- it_behaves_like "values"
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
- let(:klass) { rebase_class from: from, to: to, readable: true, convert: convert_name, deconvert: deconvert }
156
- let(:decoded) { decoded_from }
157
- let(:encoded) { encoded_convert_readable }
158
- it_behaves_like "values"
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
- let(:klass) { rebase_class(to: 16) }
239
- let(:instance) { klass.new }
279
+ rebase_classes proc { { to: 16 } } do
280
+ let(:instance) { klass.new }
240
281
 
241
- describe "#encode" do
242
- specify { expect { klass.encode_x(:a) }.to raise_error(TypeError, "decoded value must implement #to_i, :a given") }
243
- specify { expect { instance.encode_x(:a) }.to raise_error(TypeError, "decoded value must implement #to_i, :a given") }
244
- end
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
- describe "#decode" do
247
- specify { expect { klass.decode_x(:a) }.to raise_error(TypeError, "encoded value must implement #to_i, :a given") }
248
- specify { expect { instance.decode_x(:a) }.to raise_error(TypeError, "encoded value must implement #to_i, :a given") }
249
- end
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
- describe "reader" do
252
- before { instance.instance_eval { @x = :a } }
253
- specify { expect { instance.x }.to raise_error(TypeError, "decoded value must implement #to_i, :a given") }
254
- end
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
- describe "writer" do
257
- specify { expect { instance.x = :a }.to raise_error(TypeError, "encoded value must implement #to_i, :a given") }
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: 1.1.0
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-09-25 00:00:00.000000000 Z
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