striuct 0.4.3 → 0.4.4

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