striuct 0.1.7 → 0.2.3

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.
Files changed (36) hide show
  1. data/History.rdoc +43 -1
  2. data/LICENSE +22 -0
  3. data/Manifest.txt +21 -17
  4. data/{README.ja.rdoc → README.ja.old.rdoc} +11 -16
  5. data/README.rdoc +36 -250
  6. data/Rakefile +2 -2
  7. data/example/example.old.rdoc +188 -0
  8. data/example/example.rb +11 -219
  9. data/example/example1.rb +234 -0
  10. data/example/example2.rb +22 -0
  11. data/lib/striuct/abstract.rb +7 -7
  12. data/lib/striuct/conditions.rb +110 -69
  13. data/lib/striuct/{subclassable → containable}/basic.rb +9 -9
  14. data/lib/striuct/containable/classutil.rb +22 -0
  15. data/lib/striuct/{subclassable → containable}/eigen/basic.rb +9 -1
  16. data/lib/striuct/{subclassable → containable}/eigen/constructor.rb +1 -1
  17. data/lib/striuct/{subclassable → containable}/eigen/handy.rb +38 -5
  18. data/lib/striuct/{subclassable → containable}/eigen/inner.rb +22 -28
  19. data/lib/striuct/{subclassable → containable}/eigen/macro.rb +34 -25
  20. data/lib/striuct/{subclassable → containable}/eigen/safety.rb +15 -19
  21. data/lib/striuct/{subclassable/eigen/frame.rb → containable/eigen.rb} +10 -14
  22. data/lib/striuct/containable/handy.rb +91 -0
  23. data/lib/striuct/{subclassable → containable}/hashlike.rb +1 -1
  24. data/lib/striuct/{subclassable → containable}/inner.rb +23 -11
  25. data/lib/striuct/{subclassable → containable}/safety.rb +24 -5
  26. data/lib/striuct/{subclassable → containable}/yaml.rb +1 -1
  27. data/lib/striuct/containable.rb +39 -0
  28. data/lib/striuct/flavors.rb +83 -0
  29. data/lib/striuct/version.rb +2 -2
  30. data/lib/striuct.rb +13 -2
  31. data/test/test_striuct.rb +194 -17
  32. metadata +43 -35
  33. data/lib/striuct/frame.rb +0 -8
  34. data/lib/striuct/subclassable/classutil.rb +0 -26
  35. data/lib/striuct/subclassable/frame.rb +0 -33
  36. data/lib/striuct/subclassable/handy.rb +0 -57
@@ -1,9 +1,8 @@
1
- class Striuct; module Subclassable; module Eigen
1
+ class Striuct; module Containable; module Eigen
2
2
  # @group Macro for Definition
3
3
 
4
4
  private
5
5
 
6
- # @macro [attach] protect_level
7
6
  # @param [Symbol] level
8
7
  # @return [nil]
9
8
  # change protect level for risk of naming members
@@ -14,41 +13,51 @@ class Striuct; module Subclassable; module Eigen
14
13
  nil
15
14
  end
16
15
 
17
- # @macro [attach] member
16
+ VALID_MEMBER_OPTIONS = [
17
+ :inference,
18
+ :reader_validation,
19
+ :getter_validation,
20
+ :writer_validation,
21
+ :setter_validation
22
+ ].freeze
23
+
24
+ DEFAULT_MEMBER_OPTIONS = {
25
+ setter_validation: true
26
+ }.freeze
27
+
28
+ # @param [Symbol, String] name
29
+ # @param [#===, Proc, Method, ANYTHING] condition
30
+ # @param [Hash] options
18
31
  # @return [nil]
19
- def define_member(name, *conditions, &flavor)
20
- warn 'deprecated multiple conditions here, please use .#OR' if conditions.length >= 2
32
+ def add_member(name, condition=ANYTHING, options=DEFAULT_MEMBER_OPTIONS, &flavor)
21
33
  raise "already closed to add member in #{self}" if closed?
34
+ options = DEFAULT_MEMBER_OPTIONS.merge options
35
+ raise ArgumentError, 'invalid option parameter is' unless (options.keys - VALID_MEMBER_OPTIONS).empty?
22
36
  name = keyable_for name
23
37
  raise ArgumentError, %Q!already exist name "#{name}"! if member? name
24
38
  _check_safety_naming name
39
+ _mark_setter_validation name if options[:setter_validation] or options[:writer_validation]
40
+ _mark_getter_validation name if options[:getter_validation] or options[:reader_validation]
41
+ _mark_inference name if options[:inference]
25
42
 
26
43
  @names << name
27
44
  __getter__! name
28
- __setter__! name, *conditions, &flavor
45
+ __setter__! name, condition, &flavor
29
46
  nil
30
47
  end
31
48
 
32
- alias_method :def_member, :define_member
33
- alias_method :member, :define_member
49
+ alias_method :member, :add_member
34
50
 
35
- # @macro [attach] define_members
51
+ # @param [Symbol, String] name
52
+ # @param [Symbol, String] *names
36
53
  # @return [nil]
37
- def define_members(*names)
54
+ def add_members(name, *names)
38
55
  raise "already closed to add members in #{self}" if closed?
39
- unless names.length >= 1
40
- raise ArgumentError, 'wrong number of arguments (0 for 1+)'
41
- end
42
56
 
43
- names.each do |name|
44
- define_member name
45
- end
46
-
57
+ [name, *names].each {|_name|add_member _name}
47
58
  nil
48
59
  end
49
60
 
50
- alias_method :def_members, :define_members
51
-
52
61
  # @param [Symbol, String] aliased
53
62
  # @param [Symbol, String] original
54
63
  # @return [nil]
@@ -63,11 +72,10 @@ class Striuct; module Subclassable; module Eigen
63
72
  alias_method aliased, original
64
73
  alias_method "#{aliased}=", "#{original}="
65
74
  _alias_member aliased, original
66
-
67
75
  nil
68
76
  end
69
77
 
70
- # @macro [attach] default
78
+ # @param [Symbol, String] name
71
79
  # @return [nil]
72
80
  def set_default_value(name, value=nil, &block)
73
81
  raise "already closed to modify member attributes in #{self}" if closed?
@@ -77,7 +85,7 @@ class Striuct; module Subclassable; module Eigen
77
85
  value = (
78
86
  if block_given?
79
87
  if value.nil?
80
- if (arity = block.arity) == 2
88
+ if (arity = block.arity) <= 2
81
89
  SpecificContainer.new block
82
90
  else
83
91
  raise ArgumentError, "wrong number of block parameter #{arity} for 2"
@@ -97,12 +105,13 @@ class Striuct; module Subclassable; module Eigen
97
105
  alias_method :default, :set_default_value
98
106
 
99
107
  # @return [self]
100
- def fix_structural
108
+ def close_member
101
109
  [@names, @flavors, @defaults, @aliases].each(&:freeze)
102
110
  self
103
111
  end
104
112
 
105
- alias_method :close, :fix_structural
113
+ alias_method :fix_structural, :close_member
114
+ alias_method :close, :close_member
106
115
 
107
116
  # @endgroup
108
- end; end; end
117
+ end; end; end
@@ -1,10 +1,5 @@
1
- class Striuct; module Subclassable; module Eigen
1
+ class Striuct; module Containable; module Eigen
2
2
  # @group Struct+ Safety
3
-
4
- # @return [INFERENCE] specific key of inference checker
5
- def inference
6
- INFERENCE
7
- end
8
3
 
9
4
  # @param [Symbol, String] name
10
5
  # inference checker is waiting yet
@@ -15,31 +10,32 @@ class Striuct; module Subclassable; module Eigen
15
10
  end
16
11
 
17
12
  # @param [Symbol, String] name
18
- def has_conditions?(name)
13
+ def has_condition?(name)
19
14
  name = originalkey_for(keyable_for name)
20
15
 
21
16
  @conditions.has_key?(name)
22
17
  end
23
18
 
24
- alias_method :restrict?, :has_conditions?
19
+ alias_method :restrict?, :has_condition?
25
20
 
26
21
  # @param [Symbol, String] name
27
- # @param [Object] value
28
- # @param [Subclass] context - expect own instance
29
- # value can set the member space
30
- def sufficient?(name, value, context=nil)
22
+ def safety_getter?(name)
31
23
  name = originalkey_for(keyable_for name)
32
24
 
33
- if restrict? name
34
- conditions_for(name).any?{|c|pass? value, c, context}
35
- else
36
- true
37
- end
25
+ @getter_validations.has_key?(name)
38
26
  end
39
27
 
40
- alias_method :accept?, :sufficient?
41
- alias_method :valid?, :sufficient?
28
+ alias_method :safety_reader?, :safety_getter?
42
29
 
30
+ # @param [Symbol, String] name
31
+ def safety_setter?(name)
32
+ name = originalkey_for(keyable_for name)
33
+
34
+ @setter_validations.has_key?(name)
35
+ end
36
+
37
+ alias_method :safety_writer?, :safety_setter?
38
+
43
39
  # @param [Object] name
44
40
  # accpeptable the name into own member, under protect level of runtime
45
41
  def cname?(name)
@@ -1,10 +1,12 @@
1
- require_relative '../../conditions'
1
+ require_relative '../conditions'
2
+ require_relative '../flavors'
2
3
 
3
- class Striuct; module Subclassable
4
+ class Striuct; module Containable
4
5
 
5
6
  # @author Kenichi Kamiya
6
7
  module Eigen
7
8
  include Conditions
9
+ include Flavors
8
10
 
9
11
  NAMING_RISKS = {
10
12
  conflict: 10,
@@ -21,19 +23,13 @@ module Eigen
21
23
  prevent: {error: 5, warn: 1},
22
24
  nervous: {error: 1, warn: 1}
23
25
  }.each(&:freeze).freeze
24
-
25
- INFERENCE = Object.new.freeze
26
-
27
- if respond_to? :private_constant
28
- private_constant :INFERENCE
29
- end
30
26
  end
31
27
 
32
28
  end; end
33
29
 
34
- require_relative 'basic'
35
- require_relative 'constructor'
36
- require_relative 'safety'
37
- require_relative 'handy'
38
- require_relative 'macro'
39
- require_relative 'inner'
30
+ require_relative 'eigen/basic'
31
+ require_relative 'eigen/constructor'
32
+ require_relative 'eigen/safety'
33
+ require_relative 'eigen/handy'
34
+ require_relative 'eigen/macro'
35
+ require_relative 'eigen/inner'
@@ -0,0 +1,91 @@
1
+ class Striuct; module Containable
2
+ # @group Struct + Handy
3
+
4
+ # see self.class.*args
5
+ delegate_class_methods :has_default?, :default_for, :has_flavor?
6
+
7
+ # @yield [index]
8
+ # @yieldparam [Integer] index
9
+ # @yieldreturn [self]
10
+ # @return [Enumerator]
11
+ def each_index
12
+ return to_enum(__method__) unless block_given?
13
+ self.class.each_index{|index|yield index}
14
+ self
15
+ end
16
+
17
+ # @yield [name, index]
18
+ # @yieldparam [Symbol] name
19
+ # @yieldparam [Integer] index
20
+ # @yieldreturn [self]
21
+ # @return [Enumerator]
22
+ def each_name_with_index
23
+ return to_enum(__method__) unless block_given?
24
+ self.class.each_name_with_index{|name, index|yield name, index}
25
+ self
26
+ end
27
+
28
+ alias_method :each_member_with_index, :each_name_with_index
29
+ alias_method :each_key_with_index, :each_name_with_index
30
+
31
+ # @yield [value, index]
32
+ # @yieldparam [Integer] index
33
+ # @yieldreturn [self]
34
+ # @return [Enumerator]
35
+ def each_value_with_index
36
+ return to_enum(__method__) unless block_given?
37
+ each_value.with_index{|value, index|yield value, index}
38
+ self
39
+ end
40
+
41
+ alias_method :each_with_index, :each_value_with_index
42
+
43
+ # @yield [name, value, index]
44
+ # @yieldparam [Symbol] name
45
+ # @yieldparam [Integer] index
46
+ # @yieldreturn [self]
47
+ # @return [Enumerator]
48
+ def each_pair_with_index
49
+ return to_enum(__method__) unless block_given?
50
+ index = 0
51
+ each_pair do |name, value|
52
+ yield name, value, index
53
+ index += 1
54
+ end
55
+ self
56
+ end
57
+
58
+ # @param [Symbol, String] name
59
+ def assign?(name)
60
+ name = originalkey_for(keyable_for name)
61
+
62
+ @db.has_key? name
63
+ end
64
+
65
+ # @param [Symbol, String, Fixnum] key
66
+ def clear_at(key)
67
+ __subscript__(key){|name|__clear__ name}
68
+ end
69
+
70
+ alias_method :unassign, :clear_at
71
+ alias_method :reset_at, :clear_at
72
+
73
+ # @param [Symbol, String] name
74
+ def default?(name)
75
+ name = originalkey_for(keyable_for name)
76
+
77
+ default_for(name) == self[name]
78
+ end
79
+
80
+ # all members aren't assigned
81
+ def empty?
82
+ each_name.none?{|name|assign? name}
83
+ end
84
+
85
+ # @return [Struct]
86
+ def to_struct
87
+ self.class.to_struct_class.new(*values)
88
+ end
89
+
90
+ # @endgroup
91
+ end; end
@@ -1,4 +1,4 @@
1
- class Striuct; module Subclassable
1
+ class Striuct; module Containable
2
2
  # @group HashLike
3
3
 
4
4
  # @return [Hash]
@@ -1,11 +1,11 @@
1
- class Striuct; module Subclassable
1
+ class Striuct; module Containable
2
2
  private
3
3
 
4
4
  # @group Use Only Inner
5
5
 
6
6
  # see self.class.*args
7
7
  delegate_class_methods(
8
- :keyable_for, :flavor_for, :conditions_for, :originalkey_for
8
+ :keyable_for, :flavor_for, :condition_for, :originalkey_for
9
9
  )
10
10
 
11
11
  def initialize_copy(original)
@@ -14,8 +14,14 @@ class Striuct; module Subclassable
14
14
 
15
15
  def __get__(name)
16
16
  name = originalkey_for(keyable_for name)
17
+ value = @db[name]
18
+
19
+ if safety_getter?(name) and !accept?(name, value)
20
+ raise ConditionError,
21
+ "#{value.inspect} is deficient for #{name} in #{self.class}"
22
+ end
17
23
 
18
- @db[name]
24
+ value
19
25
  end
20
26
 
21
27
  def __set__(name, value)
@@ -23,13 +29,17 @@ class Striuct; module Subclassable
23
29
  name = originalkey_for(keyable_for name)
24
30
  raise "can't modify locked member #{name}" if lock? name
25
31
 
26
- unless accept? name, value
27
- raise ConditionError,
28
- "#{value.inspect} is deficient for #{conditions_for(name).inspect}"
29
- end
30
-
31
32
  if has_flavor? name
32
- value = instance_exec value, &flavor_for(name)
33
+ begin
34
+ value = instance_exec value, &flavor_for(name)
35
+ rescue Exception
36
+ raise ConditionError
37
+ end
38
+ end
39
+
40
+ if safety_setter?(name) and !accept?(name, value)
41
+ raise ConditionError,
42
+ "#{value.inspect} is deficient for #{name} in #{self.class}"
33
43
  end
34
44
 
35
45
  if inference? name
@@ -89,7 +99,9 @@ class Striuct; module Subclassable
89
99
  if has_default? name
90
100
  self[name] = (
91
101
  if (value = default_for name).kind_of? SpecificContainer
92
- value.value.call self, name
102
+ block = value.value
103
+ args = [self, name][0, block.arity]
104
+ block.call(*args)
93
105
  else
94
106
  value
95
107
  end
@@ -105,4 +117,4 @@ class Striuct; module Subclassable
105
117
  end
106
118
 
107
119
  # @endgroup
108
- end; end
120
+ end; end
@@ -1,14 +1,33 @@
1
- class Striuct; module Subclassable
1
+ class Striuct; module Containable
2
2
  # @group Struct+ Safety
3
3
 
4
4
  # see self.class.*args
5
- delegate_class_methods :restrict?, :has_conditions?, :inference?
6
-
5
+ delegate_class_methods :restrict?, :has_condition?,
6
+ :safety_getter?, :safety_reader?, :safety_setter?, :safty_writer?, :inference?
7
+
8
+ # @param [Object] value
9
+ # @param [Proc, Method, #===] condition
10
+ def pass?(value, condition)
11
+ case condition
12
+ when Conditions::ANYTHING
13
+ true
14
+ when Proc
15
+ instance_exec value, &condition
16
+ when Method
17
+ condition.call value
18
+ else
19
+ condition === value
20
+ end ? true : false
21
+ end
22
+
7
23
  # @param [Symbol, String] name
8
- # @param [Object] *values - no argument and use own
24
+ # @param [Object] value - no argument and use own
9
25
  # passed under any condition
10
26
  def sufficient?(name, value=self[name])
11
- self.class.sufficient? name, value, self
27
+ name = originalkey_for(keyable_for name)
28
+ return true unless restrict? name
29
+
30
+ pass? value, condition_for(name)
12
31
  end
13
32
 
14
33
  alias_method :accept?, :sufficient?
@@ -1,6 +1,6 @@
1
1
  autoload :YAML, 'yaml'
2
2
 
3
- class Striuct; module Subclassable
3
+ class Striuct; module Containable
4
4
  # @group for YAML
5
5
 
6
6
  # @return [String]
@@ -0,0 +1,39 @@
1
+ require_relative 'containable/classutil'
2
+ require_relative 'containable/eigen'
3
+
4
+ class Striuct
5
+
6
+ # @author Kenichi Kamiya
7
+ module Containable
8
+ extend ClassUtil
9
+ include Enumerable
10
+
11
+ class SpecificContainer
12
+ attr_reader :value
13
+
14
+ def initialize(value)
15
+ @value = value
16
+ end
17
+ end
18
+
19
+ if respond_to? :private_constant
20
+ private_constant :SpecificContainer
21
+ end
22
+
23
+ class << self
24
+ private
25
+
26
+ def included(klass)
27
+ klass.extend Eigen
28
+ end
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ require_relative 'containable/basic'
35
+ require_relative 'containable/safety'
36
+ require_relative 'containable/handy'
37
+ require_relative 'containable/hashlike'
38
+ require_relative 'containable/yaml'
39
+ require_relative 'containable/inner'
@@ -0,0 +1,83 @@
1
+ class Striuct
2
+
3
+ # Useful Flavor Builders
4
+ # @author Kenichi Kamiya
5
+ # @example overview
6
+ # class MyClass < Striuct
7
+ # member :id, &WHEN(String, PARSE(Integer))
8
+ module Flavors
9
+ module_function
10
+
11
+ # true if argument is sufficient for flavor.
12
+ # A flavor have to be arity equal 1.
13
+ # @param [Object] flavor
14
+ def adjustable?(flavor)
15
+ case flavor
16
+ when Proc
17
+ flavor.arity == 1
18
+ else
19
+ if flavor.respond_to?(:to_proc)
20
+ flavor.to_proc.arity == 1
21
+ else
22
+ false
23
+ end
24
+ end
25
+ end
26
+
27
+ alias_method :flavorable?, :adjustable?
28
+
29
+ # Apply flavor when passed condition.
30
+ # @return [lambda]
31
+ def WHEN(condition, flavor)
32
+ raise TypeError, 'wrong object for condition' unless conditionable? condition
33
+ raise TypeError, 'wrong object for flavor' unless adjustable? flavor
34
+
35
+ ->v{pass?(v, condition) ? flavor.call(v) : v}
36
+ end
37
+
38
+ # Sequencial apply all flavors.
39
+ # @return [lambda]
40
+ def REDUCE(flavor1, flavor2, *flavors)
41
+ flavors = [flavor1, flavor2, *flavors]
42
+
43
+ unless flavors.all?{|f|adjustable? f}
44
+ raise TypeError, 'wrong object for flavor'
45
+ end
46
+
47
+ ->v{
48
+ flavors.reduce(v){|ret, flavor|flavor.call ret}
49
+ }
50
+ end
51
+
52
+ alias_method :FLAVORS, :REDUCE
53
+ alias_method :INJECT, :REDUCE
54
+
55
+ # Accept any parser when that resopond to parse method.
56
+ # @return [lambda]
57
+ def PARSE(parser)
58
+ if !::Integer.equal?(parser) and !parser.respond_to?(:parse)
59
+ raise TypeError, 'wrong object for parser'
60
+ end
61
+
62
+ ->v{
63
+ if ::Integer.equal? parser
64
+ ::Kernel.Integer v
65
+ else
66
+ parser.parse(
67
+ case v
68
+ when String
69
+ v
70
+ when ->_{v.respond_to? :to_str}
71
+ v.to_str
72
+ when ->_{v.respond_to? :read}
73
+ v.read
74
+ else
75
+ raise TypeError, 'wrong object for parsing source'
76
+ end
77
+ )
78
+ end
79
+ }
80
+ end
81
+ end
82
+
83
+ end
@@ -1,4 +1,4 @@
1
1
  class Striuct
2
- VERSION = '0.1.7'.freeze
2
+ VERSION = '0.2.3'.freeze
3
3
  Version = VERSION
4
- end
4
+ end
data/lib/striuct.rb CHANGED
@@ -1,5 +1,16 @@
1
1
  # Copyright (C) 2011 Kenichi Kamiya
2
+ # Striuct
3
+ # Provides a Struct++ class.
2
4
 
3
- require_relative 'striuct/frame'
5
+ # @author Kenichi Kamiya
6
+ # @abstract
7
+ class Striuct
8
+ class ConditionError < ArgumentError; end
9
+
10
+ # namespace for .to_struct_class, #to_struct
11
+ module Structs
12
+ end
13
+ end
4
14
 
5
- StrictStruct = Striuct
15
+ require_relative 'striuct/version'
16
+ require_relative 'striuct/abstract'