striuct 0.1.7 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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'