striuct 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -94,6 +94,17 @@ foo.with_adjuster = '5'
94
94
  foo.with_adjuster #=> 5 # Casted via adjuster
95
95
  ```
96
96
 
97
+ ### Overview - Case 3
98
+
99
+ ```ruby
100
+ class UseMustOption < Striuct
101
+ member :foo, Integer, must: true
102
+ end
103
+
104
+ UseMustOption.new #=> InvalidOperationError "`foo` require a value under `must` option "
105
+ ```
106
+
107
+
97
108
  ### How to build flexible conditions ?
98
109
 
99
110
  * That from validation library.
data/example/README.rb CHANGED
@@ -43,4 +43,11 @@ foo.bar = 1.2
43
43
  #~ foo.bar = 1 #=> error
44
44
 
45
45
  foo.with_adjuster = '5'
46
- p foo.with_adjuster
46
+ p foo.with_adjuster
47
+
48
+ class UseMustOption < Striuct
49
+ member :foo, Integer, must: true
50
+ end
51
+
52
+ #~ p UseMustOption.new #=> InvalidOperationError
53
+ p UseMustOption.new(1)
data/lib/striuct.rb CHANGED
@@ -3,6 +3,10 @@
3
3
 
4
4
  # @abstract
5
5
  class Striuct
6
+
7
+ class Error < StandardError; end
8
+ class InvalidOperationError < Error; end
9
+
6
10
  end
7
11
 
8
12
  require_relative 'striuct/requirements'
@@ -1,17 +1,19 @@
1
1
  class Striuct; module ClassMethods
2
2
 
3
- # Attributes for each Member(Autonym)
3
+ # Attributes for autonym of each member
4
4
  class Attributes
5
5
 
6
6
  VALUES = [ :condition,
7
7
  :adjuster ].freeze
8
8
 
9
9
  BOOLEANS = [ :inference,
10
+ :must,
10
11
  :safety_setter,
11
12
  :safety_getter ].freeze
12
13
 
13
14
  def initialize
14
15
  @hash = { inference: false,
16
+ must: false,
15
17
  safety_setter: false,
16
18
  safety_getter: false }
17
19
  end
@@ -47,7 +49,7 @@ class Striuct; module ClassMethods
47
49
  @hash.fetch role
48
50
  end
49
51
 
50
- define_method "#{role}=".to_sym do |arg|
52
+ define_method :"#{role}=" do |arg|
51
53
  raise TypeError unless arg.equal?(true) or arg.equal?(false)
52
54
 
53
55
  @hash[role] = arg
@@ -17,13 +17,11 @@ class Striuct; module ClassMethods
17
17
  def for_pairs(pairs)
18
18
  raise TypeError, 'no pairs object' unless pairs.respond_to?(:each_pair)
19
19
  KeyValidatable.validate_array KeyValidatable.keys_for(pairs).map(&:to_sym),
20
- let: all_members
20
+ let: all_members
21
21
 
22
- new.tap {|instance|
23
- pairs.each_pair do |name, value|
24
- instance[name] = value
25
- end
26
- }
22
+ instance = allocate
23
+ instance.__send__ :initialize_for_pairs, pairs
24
+ instance
27
25
  end
28
26
 
29
27
  alias_method :[], :for_pairs
@@ -2,6 +2,17 @@ class Striuct; module ClassMethods
2
2
 
3
3
  # @group Inner Methods
4
4
 
5
+ # for debug
6
+ # @return [Hash]
7
+ def attributes
8
+ {
9
+ autonyms: @autonyms.dup,
10
+ aliases: @aliases.dup,
11
+ conflict_management_level: @conflict_management_level,
12
+ attributes_each_autonym: @attributes.dup
13
+ }
14
+ end
15
+
5
16
  private
6
17
 
7
18
  def _init
@@ -10,6 +10,7 @@ class Striuct; module ClassMethods
10
10
  opt :default_proc, aliases: [:lazy_default]
11
11
  conflict :default_value, :default_proc
12
12
  opt :inference, default: false
13
+ opt :must, default: false
13
14
  opt :setter_validation, aliases: [:writer_validation], default: true
14
15
  opt :getter_validation, aliases: [:reader_validation], default: false
15
16
  }
@@ -22,6 +23,7 @@ class Striuct; module ClassMethods
22
23
  # @option options [BasicObject] :default
23
24
  # @option options [Proc] :default_proc
24
25
  # @option options [Boolean] :inference
26
+ # @option options [Boolean] :must
25
27
  # @option options [Boolean] :reader_validation
26
28
  # @option options [Boolean] :getter_validation
27
29
  # @option options [Boolean] :writer_validation
@@ -45,6 +47,10 @@ class Striuct; module ClassMethods
45
47
  _attributes_for(autonym).inference = true
46
48
  end
47
49
 
50
+ if options.must
51
+ _attributes_for(autonym).must = true
52
+ end
53
+
48
54
  _def_getter autonym
49
55
  _def_setter autonym, condition, &adjuster
50
56
 
@@ -92,6 +92,17 @@ class Striuct; module ClassMethods
92
92
  _attributes_for(autonym).with_inference?
93
93
  end
94
94
 
95
+ # @param [Symbol, String, #to_sym, Integer, #to_int] key - name / index
96
+ def with_must?(key)
97
+ autonym = autonym_for_key key
98
+ rescue Exception
99
+ false
100
+ else
101
+ _attributes_for(autonym).with_must?
102
+ end
103
+
104
+ alias_method :must?, :with_must?
105
+
95
106
  # @param [Symbol, String, #to_sym, Integer, #to_int] key - name / index
96
107
  def with_safety_getter?(key)
97
108
  autonym = autonym_for_key key
@@ -14,6 +14,9 @@ class Striuct; module InstanceMethods
14
14
  def unassign(key)
15
15
  _check_frozen
16
16
  _check_locked key
17
+ if must? key
18
+ raise InvalidOperationError, "`#{key}` require a value under `must` option"
19
+ end
17
20
 
18
21
  @db.delete autonym_for_key(key)
19
22
  end
@@ -8,7 +8,7 @@ class Striuct; module InstanceMethods
8
8
  :autonym_for_member,
9
9
  :autonym_for_index,
10
10
  :autonym_for_key,
11
- :autonyms, :members, :all_members, :aliases,
11
+ :autonyms, :members, :all_members, :aliases, :attributes,
12
12
  :has_autonym?, :autonym?,
13
13
  :has_alias?, :alias?, :aliased?,
14
14
  :has_member?, :member?,
@@ -22,6 +22,7 @@ class Striuct; module InstanceMethods
22
22
  :with_safety_getter?, :with_safety_reader?,
23
23
  :with_safety_setter?, :with_safety_writer?,
24
24
  :with_inference?,
25
+ :with_must?, :must?,
25
26
  :with_default?,
26
27
  :default_value_for, :default_type_for,
27
28
  :with_adjuster?,
@@ -1,26 +1,52 @@
1
1
  class Striuct; module InstanceMethods
2
2
 
3
3
  # @group Basic Methods for Ruby's Object
4
-
5
- def initialize(*values)
6
- @db, @locks = {}, {}
7
- replace_values(*values)
8
- excess_autonyms = _autonyms.last(size - values.size)
9
- _set_defaults(*excess_autonyms)
10
- end
11
4
 
12
5
  # @return [self]
13
6
  def freeze
14
7
  @db.freeze; @locks.freeze
15
8
  super
16
9
  end
17
-
10
+
18
11
  private
12
+
13
+ def initialize(*values)
14
+ _initialize_database
15
+
16
+ replace_values(*values)
17
+ excess_autonyms = _autonyms.last(size - values.size)
18
+ _set_defaults(*excess_autonyms)
19
+
20
+ each_autonym do |autonym|
21
+ _check_must autonym
22
+ end
23
+ end
24
+
25
+ def initialize_for_pairs(pairs)
26
+ _initialize_database
27
+
28
+ excess_autonyms = _autonyms.dup
29
+ pairs.each_pair do |key, value|
30
+ autonym = autonym_for_key key
31
+ self[autonym] = value
32
+ excess_autonyms.delete autonym
33
+ end
34
+
35
+ _set_defaults(*excess_autonyms)
36
+
37
+ excess_autonyms.each do |autonym|
38
+ _check_must autonym
39
+ end
40
+ end
19
41
 
20
42
  def initialize_copy(original)
21
43
  @db, @locks = @db.dup, {}
22
44
  end
23
45
 
46
+ def _initialize_database
47
+ @db, @locks = {}, {}
48
+ end
49
+
24
50
  def _check_frozen
25
51
  raise "can't modify frozen #{self.class}" if frozen?
26
52
  end
@@ -29,6 +55,12 @@ class Striuct; module InstanceMethods
29
55
  raise "can't modify locked member `#{key}`" if locked? key
30
56
  end
31
57
 
58
+ def _check_must(key)
59
+ if must?(key) && !assigned?(key)
60
+ raise InvalidOperationError, "`#{key}` require a value under `must` option"
61
+ end
62
+ end
63
+
32
64
  # @endgroup
33
65
 
34
66
  end; end
@@ -4,13 +4,21 @@ class Striuct; module InstanceMethods
4
4
 
5
5
  # @return [String]
6
6
  def inspect
7
- "#<struct' #{self.class} strict?:#{strict?}".tap {|s|
7
+ "#<struct' #{self.class}".tap {|s|
8
8
  each_pair do |autonym, value|
9
9
  suffix = (with_default?(autonym) && default?(autonym)) ? '/default' : nil
10
- s << " #{autonym}=#{value.inspect}#{suffix}("
11
- s << "valid?:#{valid? autonym}, "
12
- s << "locked?:#{locked? autonym}"
13
- s << '),'
10
+ label_valid = valid?(autonym) ? nil : :invalid
11
+ label_lock = locked?(autonym) ? :locked : nil
12
+ label_must = must?(autonym) ? :must : nil
13
+ labels = [label_valid, label_lock, label_must].select{|_|_}
14
+
15
+ s << " #{autonym}=#{value.inspect}#{suffix}"
16
+ unless labels.empty?
17
+ s << '('
18
+ s << labels.join(', ')
19
+ s << ')'
20
+ end
21
+ s << ','
14
22
  end
15
23
 
16
24
  s.chop!
data/striuct.gemspec CHANGED
@@ -1,7 +1,9 @@
1
1
  Gem::Specification.new do |gem|
2
2
  # specific
3
3
 
4
- gem.description = %q{Struct++ library
4
+ gem.description = %q{Struct++ library.
5
+
6
+ ---
5
7
 
6
8
  Validatable, Inheritable, Member Aliasing,
7
9
  Conflict Management, Default Value, Divide nil with unassign,
@@ -11,7 +13,7 @@ Gem::Specification.new do |gem|
11
13
  gem.homepage = 'http://kachick.github.com/striuct/'
12
14
  gem.license = 'MIT'
13
15
  gem.name = 'striuct'
14
- gem.version = '0.4.3'
16
+ gem.version = '0.4.4'
15
17
 
16
18
  gem.required_ruby_version = '>= 1.9.2'
17
19
 
@@ -382,6 +382,70 @@ class Test_Striuct_Subclass_Predicate_InferenceValidation < Test::Unit::TestCase
382
382
 
383
383
  end
384
384
 
385
+ class Test_Striuct_Subclass_Predicate_Must < Test::Unit::TestCase
386
+
387
+ class Subclass < Striuct
388
+ member :no_with
389
+ alias_member :als_no_with, :no_with
390
+ member :with, BasicObject, must: true
391
+ alias_member :als_with, :with
392
+ member :with_any, BasicObject, must: true
393
+ alias_member :als_with_any, :with_any
394
+ member(:adj_with, BasicObject, must: true) do |_|; end
395
+ alias_member :als_adj_with, :adj_with
396
+
397
+ close_member
398
+ end.freeze
399
+
400
+ INSTANCE = Subclass[als_with: 1, als_with_any: 1, adj_with: 1].freeze
401
+
402
+ TYPE_PAIRS = {
403
+ class: Subclass,
404
+ instance: INSTANCE
405
+ }.freeze
406
+
407
+ [:with_must?, :must?].each do |predicate|
408
+ TYPE_PAIRS.each_pair do |type, reciever|
409
+ define_method :"test_#{type}_#{predicate}" do
410
+ assert_same false, reciever.public_send(predicate, :no_with)
411
+ assert_same false, reciever.public_send(predicate, :als_no_with)
412
+ assert_same false, reciever.public_send(predicate, 'no_with')
413
+ assert_same false, reciever.public_send(predicate, 'als_no_with')
414
+ assert_same false, reciever.public_send(predicate, 0)
415
+ assert_same false, reciever.public_send(predicate, 0.9)
416
+
417
+ assert_same true, reciever.public_send(predicate, :with)
418
+ assert_same true, reciever.public_send(predicate, :als_with)
419
+ assert_same true, reciever.public_send(predicate, 'with')
420
+ assert_same true, reciever.public_send(predicate, 'als_with')
421
+ assert_same true, reciever.public_send(predicate, 1)
422
+ assert_same true, reciever.public_send(predicate, 1.9)
423
+
424
+ assert_same true, reciever.public_send(predicate, :with_any)
425
+ assert_same true, reciever.public_send(predicate, :als_with_any)
426
+ assert_same true, reciever.public_send(predicate, 'with_any')
427
+ assert_same true, reciever.public_send(predicate, 'als_with_any')
428
+ assert_same true, reciever.public_send(predicate, 2)
429
+ assert_same true, reciever.public_send(predicate, 2.9)
430
+
431
+ assert_same true, reciever.public_send(predicate, :adj_with)
432
+ assert_same true, reciever.public_send(predicate, :als_adj_with)
433
+ assert_same true, reciever.public_send(predicate, 'adj_with')
434
+ assert_same true, reciever.public_send(predicate, 'als_adj_with')
435
+ assert_same true, reciever.public_send(predicate, 3)
436
+ assert_same true, reciever.public_send(predicate, 3.9)
437
+
438
+ assert_same false, reciever.public_send(predicate, :none)
439
+ assert_same false, reciever.public_send(predicate, 'none')
440
+ assert_same false, reciever.public_send(predicate, 4)
441
+ assert_same false, reciever.public_send(predicate, 4.9)
442
+ assert_same false, reciever.public_send(predicate, BasicObject.new)
443
+ end
444
+ end
445
+ end
446
+
447
+ end
448
+
385
449
 
386
450
  class Test_Striuct_Subclass_Predicate_HookTiming_Setter_Enable < Test::Unit::TestCase
387
451
 
@@ -0,0 +1,39 @@
1
+ require_relative 'helper'
2
+
3
+ class Test_Striuct_Subclass_Debug < Test::Unit::TestCase
4
+
5
+ Subclass = Striuct.define do
6
+ member :foo
7
+ member :bar
8
+ alias_member :als_foo, :foo
9
+ end.freeze
10
+
11
+ INSTANCE = Subclass.new.freeze
12
+
13
+ TYPE_PAIRS = {
14
+ Class: Subclass,
15
+ Instance: INSTANCE
16
+ }.freeze
17
+
18
+ [:attributes].each do |callee|
19
+ TYPE_PAIRS.each_pair do |type, reciever|
20
+ define_method :"test_#{type}_#{callee}" do
21
+ assert_same true, reciever.public_methods.include?(callee)
22
+ ret = reciever.public_send(callee)
23
+ assert_instance_of Hash, ret
24
+ assert_equal [:autonyms, :aliases, :conflict_management_level, :attributes_each_autonym], ret.keys
25
+ assert_equal Subclass.autonyms, ret.fetch(:autonyms)
26
+ assert_equal Subclass.aliases, ret.fetch(:aliases)
27
+ assert_equal Subclass.conflict_management_level, ret.fetch(:conflict_management_level)
28
+ assert_equal Subclass.instance_variable_get(:@attributes), ret.fetch(:attributes_each_autonym)
29
+
30
+ 10.times do
31
+ ret2 = reciever.public_send(callee)
32
+ assert_not_same ret, ret2
33
+ assert_equal ret, ret2
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,30 @@
1
+ require_relative 'helper'
2
+
3
+ class Test_Striuct_Subclass_Must < Test::Unit::TestCase
4
+
5
+ Sth = Striuct.define do
6
+ member :foo, ANYTHING?, must: false
7
+ member :bar, ANYTHING?, must: true
8
+ member :baz
9
+ end
10
+
11
+ def test_must
12
+ assert_raises(Striuct::InvalidOperationError) do
13
+ Sth.new :foo
14
+ end
15
+
16
+ assert_raises(Striuct::InvalidOperationError) do
17
+ Sth.new foo: :foo, baz: :baz
18
+ end
19
+
20
+ sth = Sth.new :foo, :bar, :baz
21
+ assert_instance_of(Sth, sth)
22
+
23
+ assert_raises(Striuct::InvalidOperationError) do
24
+ sth.unassign :bar
25
+ end
26
+
27
+ assert_nil(sth.bar = nil)
28
+ end
29
+
30
+ end
@@ -3,23 +3,24 @@ require_relative 'helper'
3
3
  class Test_Striuct_Subclass_Instance_to_s_Family < Test::Unit::TestCase
4
4
 
5
5
  class User < Striuct.new
6
- member :id, Integer
7
- member :last_name, /\A\w+\z/
8
- member :family_name, /\A\w+\z/
9
- member :address, /\A((\w+) ?)+\z/
10
- member :age, ->age{(20..140).include? age}
6
+ member :id, Integer, must: true
7
+ member :name, /\w+/
8
+ end
9
+
10
+ def setup
11
+ @sth = User.new 9999, 'taro'
12
+ @sth.lock(:name)
13
+ @sth.name.clear
11
14
  end
12
15
 
13
16
  def test_to_s
14
- user = User.new 9999, 'taro', 'yamada', 'Tokyo Japan', 30
15
- assert_equal %q!#<struct' Test_Striuct_Subclass_Instance_to_s_Family::User id=9999, last_name="taro", family_name="yamada", address="Tokyo Japan", age=30>!,
16
- user.to_s
17
+ assert_equal %q!#<struct' Test_Striuct_Subclass_Instance_to_s_Family::User id=9999, name="">!,
18
+ @sth.to_s
17
19
  end
18
20
 
19
21
  def test_inspect
20
- user = User.new 9999, 'taro', 'yamada', 'Tokyo Japan', 30
21
- assert_equal %q!#<struct' Test_Striuct_Subclass_Instance_to_s_Family::User strict?:true id=9999(valid?:true, locked?:false), last_name="taro"(valid?:true, locked?:false), family_name="yamada"(valid?:true, locked?:false), address="Tokyo Japan"(valid?:true, locked?:false), age=30(valid?:true, locked?:false)>!,
22
- user.inspect
22
+ assert_equal %q!#<struct' Test_Striuct_Subclass_Instance_to_s_Family::User id=9999(must), name=""(invalid, locked)>!,
23
+ @sth.inspect
23
24
  end
24
25
 
25
26
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: striuct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.4.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-31 00:00:00.000000000 Z
12
+ date: 2013-06-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: validation
@@ -125,7 +125,7 @@ dependencies:
125
125
  - - <
126
126
  - !ruby/object:Gem::Version
127
127
  version: '2'
128
- description: ! "Struct++ library\n\n Validatable, Inheritable, Member Aliasing,\n
128
+ description: ! "Struct++ library.\n\n---\n\n Validatable, Inheritable, Member Aliasing,\n
129
129
  \ Conflict Management, Default Value, Divide nil with unassign,\n Lock setter of
130
130
  each member, Hash flendly API, ... And more Struct++ features :)"
131
131
  email:
@@ -202,6 +202,7 @@ files:
202
202
  - test/test_subc-f-predicate.rb
203
203
  - test/test_subc-f-to_struct.rb
204
204
  - test/test_subc-f-validation_util.rb
205
+ - test/test_subc-f_debug.rb
205
206
  - test/test_subc-f_name.rb
206
207
  - test/test_subc-i-accessor.rb
207
208
  - test/test_subc-i-adjuster.rb
@@ -215,6 +216,7 @@ files:
215
216
  - test/test_subc-i-hashlike.rb
216
217
  - test/test_subc-i-keyvalidatable.rb
217
218
  - test/test_subc-i-lock.rb
219
+ - test/test_subc-i-must.rb
218
220
  - test/test_subc-i-to_s_family.rb
219
221
  - test/test_subc-i-validation_inference.rb
220
222
  - test/test_subc-i-validation_specific_conditions.rb
@@ -244,9 +246,9 @@ rubyforge_project:
244
246
  rubygems_version: 1.8.23
245
247
  signing_key:
246
248
  specification_version: 3
247
- summary: Struct++ library Validatable, Inheritable, Member Aliasing, Conflict Management,
248
- Default Value, Divide nil with unassign, Lock setter of each member, Hash flendly
249
- API, ... And more Struct++ features :)
249
+ summary: Struct++ library. --- Validatable, Inheritable, Member Aliasing, Conflict
250
+ Management, Default Value, Divide nil with unassign, Lock setter of each member,
251
+ Hash flendly API, ... And more Struct++ features :)
250
252
  test_files:
251
253
  - test/helper.rb
252
254
  - test/test_sglc-constructor.rb
@@ -262,6 +264,7 @@ test_files:
262
264
  - test/test_subc-f-predicate.rb
263
265
  - test/test_subc-f-to_struct.rb
264
266
  - test/test_subc-f-validation_util.rb
267
+ - test/test_subc-f_debug.rb
265
268
  - test/test_subc-f_name.rb
266
269
  - test/test_subc-i-accessor.rb
267
270
  - test/test_subc-i-adjuster.rb
@@ -275,6 +278,7 @@ test_files:
275
278
  - test/test_subc-i-hashlike.rb
276
279
  - test/test_subc-i-keyvalidatable.rb
277
280
  - test/test_subc-i-lock.rb
281
+ - test/test_subc-i-must.rb
278
282
  - test/test_subc-i-to_s_family.rb
279
283
  - test/test_subc-i-validation_inference.rb
280
284
  - test/test_subc-i-validation_specific_conditions.rb