@@ -6,91 +6,103 @@ def self.included(base)
66 base . extend ( ClassMethods )
77 end
88
9+ def initialize ( *values )
10+ @values = values
11+ check_fields_are_initialized
12+ set_instance_variables
13+ check_invariants
14+ end
15+
16+ def eql? ( other )
17+ self . class == other . class && values == other . values
18+ end
19+
20+ def ==( other )
21+ eql? ( other )
22+ end
23+
24+ def hash
25+ self . class . hash ^ values . hash
26+ end
27+
28+ protected
29+
30+ def values
31+ @values
32+ end
33+
34+ private
35+
36+ def names
37+ self . class . field_names
38+ end
39+
40+ def predicates
41+ self . class . predicate_symbols
42+ end
43+
44+ def check_fields_are_initialized
45+ raise WrongNumberOfArguments . new ( names . length , values . length ) unless arguments_number_is_right?
46+ raise FieldWithoutValue . new ( uninitialized_field_names ) unless all_fields_initialized?
47+ end
48+
49+ def set_instance_variables
50+ names . zip ( values ) do |name , value |
51+ instance_variable_set ( :"@#{ name } " , value )
52+ end
53+ end
54+
55+ def arguments_number_is_right?
56+ values . length == names . length
57+ end
58+
59+ def uninitialized_fields
60+ names . zip ( values ) . select { |name , value | value . nil? }
61+ end
62+
63+ def all_fields_initialized?
64+ uninitialized_fields . empty?
65+ end
66+
67+ def uninitialized_field_names
68+ uninitialized_fields . map { |field | field . first }
69+ end
70+
71+ def check_invariants
72+ return if predicates . nil?
73+
74+ predicates . each do |predicate |
75+ valid = invariant_holds? ( predicate )
76+ raise ViolatedInvariant . new ( predicate , values ) unless valid
77+ end
78+ end
79+
80+ def invariant_holds? ( predicate_symbol )
81+ begin
82+ valid = send ( predicate_symbol )
83+ rescue
84+ raise NotImplementedInvariant . new ( predicate_symbol )
85+ end
86+ end
87+
988 module ClassMethods
89+ def field_names
90+ @field_names
91+ end
92+
93+ def predicate_symbols
94+ @predicate_symbols
95+ end
96+
1097 def fields ( *names )
11- raise NotDeclaredFields . new ( ) if names . empty? ( )
98+ raise NotDeclaredFields . new if names . empty?
1299
13100 attr_reader ( *names )
14-
15- define_method ( :initialize ) do |*values |
16- check_fields_are_initialized ( values )
17- set_instance_variables ( values )
18- check_invariants ( )
19- end
20-
21- define_method ( :eql? ) do |other |
22- self . class == other . class && values == other . values
23- end
24-
25- define_method ( :== ) do |other |
26- eql? ( other )
27- end
28-
29- define_method ( :hash ) do
30- self . class . hash ^ values . hash
31- end
32-
33- define_method ( :values ) do
34- names . map { |field | send ( field ) }
35- end
36- protected ( :values )
37-
38- define_method ( :check_invariants ) do
39- end
40- private ( :check_invariants )
41-
42- define_method ( :check_fields_are_initialized ) do |values |
43- raise WrongNumberOfArguments . new ( names . length , values . length ) unless arguments_number_is_right? ( values )
44- raise FieldWithoutValue . new ( uninitialized_fields_names ( values ) ) unless all_fields_initialized? ( values )
45- end
46- private ( :check_fields_are_initialized )
47-
48- define_method ( :arguments_number_is_right? ) do |values |
49- fields_number = names . length
50- arguments_number = values . length
51- values . length == names . length
52- end
53- private ( :arguments_number_is_right? )
54-
55- define_method ( :uninitialized_fields ) do |values |
56- names . zip ( values ) . select { |name , value | value . nil? }
57- end
58- private ( :uninitialized_fields )
59-
60- define_method ( :all_fields_initialized? ) do |values |
61- uninitialized_fields ( values ) . empty?
62- end
63- private ( :all_fields_initialized? )
64-
65- define_method ( :uninitialized_fields_names ) do |values |
66- uninitialized_fields ( values ) . map { |field | field . first }
67- end
68- private ( :uninitialized_fields_names )
69-
70- define_method ( :set_instance_variables ) do |values |
71- names . zip ( values ) do |name , value |
72- instance_variable_set ( :"@#{ name } " , value )
73- end
74- end
75- private ( :set_instance_variables )
101+ @field_names = names
76102 end
77103
78104 def invariants ( *predicate_symbols )
79- define_method ( :check_invariants ) do
80- predicate_symbols . each do |predicate_symbol |
81- valid = invariant_holds? ( predicate_symbol )
82- raise ViolatedInvariant . new ( predicate_symbol , self . values ) unless valid
83- end
84- end
85-
86- define_method ( :invariant_holds? ) do |predicate_symbol |
87- begin
88- valid = send ( predicate_symbol )
89- rescue
90- raise NotImplementedInvariant . new ( predicate_symbol )
91- end
92- end
93- private ( :invariant_holds? )
105+ @predicate_symbols = predicate_symbols
94106 end
95107 end
96108end
0 commit comments