Module: NeuronCheckSystem::Kernel
- Defined in:
- lib/neuroncheck/kernel.rb
Overview
メソッド追加時のフック処理や、属性宣言メソッドのオーバーライドなどを定義したメインモジュールNeuronCheckを行いたい対象のモジュールやクラスにextendすることで使用する
Instance Method Summary collapse
- #__neuron_check_attr_defined(used_method_name, names, use_reader: false, use_writer: false) ⇒ Object
-
#__neuron_check_method_added_hook(target_cls_or_mod, method_name, met, singleton_original_class = nil) ⇒ Object
メソッド/特異メソッドを定義したときの共通処理.
-
#attr(name, assignable = false) ⇒ Object
属性定義.
- #attr_accessor(*names) ⇒ Object
- #attr_reader(*names) ⇒ Object
- #attr_writer(*names) ⇒ Object
-
#method_added(name) ⇒ Object
インスタンスメソッド定義を追加したときの処理.
-
#singleton_method_added(name) ⇒ Object
特異メソッド定義を追加したときの処理.
Instance Method Details
#__neuron_check_attr_defined(used_method_name, names, use_reader: false, use_writer: false) ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/neuroncheck/kernel.rb', line 65 def __neuron_check_attr_defined(used_method_name, names, use_reader: false, use_writer: false) # 直前にNeuronCheck宣言部があれば、その宣言内容を各メソッドへ登録する if (declaration = @__neuron_check_last_declaration) then # 短縮記法による宣言かどうかで分岐 if declaration.shorthand then # 短縮記法の場合は、引数が2つ以上宣言されている、もしくは戻り値が宣言されている場合にエラーとする if declaration.arg_matchers.size >= 2 or declaration.return_matcher then raise NeuronCheckSystem::DeclarationError, "expected value must be one for `#{used_method_name}'", declaration.declared_caller_locations end # 引数1用のマッチャを属性用のマッチャとみなす target_attr_matcher = declaration.arg_matchers[0] else # 通常の宣言の場合、引数、戻り値の宣言がされている場合はエラーとする if declaration.arg_matchers.size >= 1 or declaration.return_matcher then raise NeuronCheckSystem::DeclarationError, "`args' or `returns' declaration can be used only for method definition, but used for `#{used_method_name}'", declaration.declared_caller_locations end target_attr_matcher = declaration.attr_matcher end # 属性チェック用モジュールに対する処理 @__neuron_check_attr_check_module.module_eval do # 属性1つごとに処理 names.each do |attr_name| # 属性チェック用モジュールに、readerチェック用のラッパーメソッドを追加する if use_reader then define_method(attr_name) do # 通常の処理を呼び出す val = super() # 属性宣言があればチェック処理 if target_attr_matcher then unless target_attr_matcher.match?(val, self) then context_caption = "value of attribute `#{self.class.name}##{attr_name}'" raise NeuronCheckError, target_attr_matcher.(declaration, context_caption, val), (NeuronCheck.debug? ? caller : caller(1)) end end end end # 属性チェック用モジュールに、writerチェック用のラッパーメソッドを追加する if use_writer then define_method("#{attr_name}=") do |val| # 属性宣言があればチェック処理 if target_attr_matcher then unless target_attr_matcher.match?(val, self) then context_caption = "value of attribute `#{self.class.name}##{attr_name}'" raise NeuronCheckError, target_attr_matcher.(declaration, context_caption, val, phrase_after_but: 'set'), (NeuronCheck.debug? ? caller : caller(1)) end end # 通常の処理を呼び出す super(val) end end end end # 属性1つごとに処理 names.each do |attr_name| # 登録実行 NeuronCheckSystem::ATTR_DECLARATIONS[self][attr_name] = declaration declaration.assigned_class_or_module = self declaration.assigned_attribute_name = attr_name end # チェック処理の追加が完了したら、「最後に宣言した内容」を表すクラスインスタンス変数をnilに戻す @__neuron_check_last_declaration = nil end end |
#__neuron_check_method_added_hook(target_cls_or_mod, method_name, met, singleton_original_class = nil) ⇒ Object
メソッド/特異メソッドを定義したときの共通処理
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/neuroncheck/kernel.rb', line 159 def __neuron_check_method_added_hook(target_cls_or_mod, method_name, met, singleton_original_class = nil) singleton = !(singleton_original_class.nil?) # メソッド定義時のフックが無効化されている場合は何もしない return unless @__neuron_check_method_added_hook_enabled # 直前にNeuronCheck宣言部があれば、その宣言内容を登録する if (declaration = @__neuron_check_last_declaration) then # あらかじめ登録と、メソッドやクラスとの紐付けを行っておく # この処理を先に行わないと正しく名前を取得できない NeuronCheckSystem::METHOD_DECLARATIONS[target_cls_or_mod][method_name] = declaration declaration.assigned_class_or_module = target_cls_or_mod declaration.assigned_method = met declaration.assigned_singleton_original_class = singleton_original_class # 宣言に引数チェックが含まれている場合、宣言部の引数の数が、実際のメソッドの引数の数を超えていないかをチェック # 超えていれば宣言エラーとする if declaration.arg_matchers.size > met.parameters.size then raise NeuronCheckSystem::DeclarationError, "given arguments number of ##{method_name} greater than method definition - expected #{met.parameters.size} args, but #{declaration.arg_matchers.size} args were declared" end # パラメータの中にブロック型の引数が含まれているが # そのパラメータが、anyでもblockでもない型である場合はエラー met.parameters.each_with_index do |param_info, def_param_index| param_type, param_name = param_info if param_type == :block and (matcher = declaration.arg_matchers[def_param_index]) then next if matcher.respond_to?(:keyword_name) and matcher.keyword_name == 'any' next if matcher.respond_to?(:keyword_name) and matcher.keyword_name == 'block' context_caption = "#{NeuronCheckSystem::Utils.ordinalize(def_param_index + 1)} argument `#{param_name}' of `#{declaration.signature_caption_name_only}'" raise NeuronCheckSystem::DeclarationError, "#{context_caption} is block argument - it can be specified only keyword `any' or `block'" end end # 特異メソッドでなく、メソッド名が「initialize」であるにもかかわらず、returns宣言が含まれている場合はエラー if not singleton and method_name == :initialize and declaration.return_matcher then raise NeuronCheckSystem::DeclarationError, "returns declaration cannot be used with `#initialize' method" end # チェック処理の追加が完了したら、「最後に宣言した内容」を表すクラスインスタンス変数をnilに戻す @__neuron_check_last_declaration = nil end end |
#attr(name, assignable = false) ⇒ Object
属性定義
13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/neuroncheck/kernel.rb', line 13 def attr(name, assignable = false) @__neuron_check_method_added_hook_enabled = false begin # 元処理を呼ぶ super # NeuronCheck用の属性定義時処理を呼ぶ __neuron_check_attr_defined(__method__, [name], use_reader: true, use_writer: assignable) ensure @__neuron_check_method_added_hook_enabled = true end end |
#attr_accessor(*names) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/neuroncheck/kernel.rb', line 52 def attr_accessor(*names) @__neuron_check_method_added_hook_enabled = false begin # 元処理を呼ぶ super # NeuronCheck用の属性定義時処理を呼ぶ __neuron_check_attr_defined(__method__, names, use_reader: true, use_writer: true) ensure @__neuron_check_method_added_hook_enabled = true end end |
#attr_reader(*names) ⇒ Object
26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/neuroncheck/kernel.rb', line 26 def attr_reader(*names) @__neuron_check_method_added_hook_enabled = false begin # 元処理を呼ぶ super # NeuronCheck用の属性定義時処理を呼ぶ __neuron_check_attr_defined(__method__, names, use_reader: true, use_writer: false) ensure @__neuron_check_method_added_hook_enabled = true end end |
#attr_writer(*names) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/neuroncheck/kernel.rb', line 39 def attr_writer(*names) @__neuron_check_method_added_hook_enabled = false begin # 元処理を呼ぶ super # NeuronCheck用の属性定義時処理を呼ぶ __neuron_check_attr_defined(__method__, names, use_reader: false, use_writer: true) ensure @__neuron_check_method_added_hook_enabled = true end end |
#method_added(name) ⇒ Object
インスタンスメソッド定義を追加したときの処理
141 142 143 144 145 146 147 |
# File 'lib/neuroncheck/kernel.rb', line 141 def method_added(name) # まずは親処理を呼ぶ super # メイン処理をコール __neuron_check_method_added_hook(self, name, self.instance_method(name)) end |
#singleton_method_added(name) ⇒ Object
特異メソッド定義を追加したときの処理
150 151 152 153 154 155 156 |
# File 'lib/neuroncheck/kernel.rb', line 150 def singleton_method_added(name) # まずは親処理を呼ぶ super # メイン処理をコール __neuron_check_method_added_hook(self.singleton_class, name, self.singleton_class.instance_method(name), self) end |