when_exe 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/LICENSE.ja.txt +25 -25
  2. data/LICENSE.txt +31 -31
  3. data/bin/locales.rb +2 -1
  4. data/bin/when.rb.config +1 -1
  5. data/lib/when_exe.rb +70 -48
  6. data/lib/when_exe/basictypes.rb +99 -65
  7. data/lib/when_exe/calendartypes.rb +40 -178
  8. data/lib/when_exe/coordinates.rb +156 -62
  9. data/lib/when_exe/core/compatibility.rb +10 -0
  10. data/lib/when_exe/core/extension.rb +40 -0
  11. data/lib/when_exe/ephemeris.rb +112 -50
  12. data/lib/when_exe/icalendar.rb +125 -91
  13. data/lib/when_exe/inspect.rb +100 -48
  14. data/lib/when_exe/locales/ar.rb +48 -48
  15. data/lib/when_exe/locales/bg.rb +1 -1
  16. data/lib/when_exe/locales/bs.rb +4 -2
  17. data/lib/when_exe/locales/ca.rb +1 -1
  18. data/lib/when_exe/locales/en_CA.rb +3 -4
  19. data/lib/when_exe/locales/en_IE.rb +88 -0
  20. data/lib/when_exe/locales/en_US.rb +87 -0
  21. data/lib/when_exe/locales/es_CR.rb +84 -0
  22. data/lib/when_exe/locales/es_EC.rb +85 -0
  23. data/lib/when_exe/locales/es_PA.rb +85 -0
  24. data/lib/when_exe/locales/fr.rb +39 -39
  25. data/lib/when_exe/locales/hu.rb +15 -14
  26. data/lib/when_exe/locales/it.rb +1 -1
  27. data/lib/when_exe/locales/ja.rb +2 -2
  28. data/lib/when_exe/locales/locales.rb +7 -0
  29. data/lib/when_exe/locales/lt.rb +21 -19
  30. data/lib/when_exe/locales/ms.rb +84 -0
  31. data/lib/when_exe/locales/nl.rb +2 -2
  32. data/lib/when_exe/locales/ru.rb +1 -1
  33. data/lib/when_exe/locales/uk.rb +1 -1
  34. data/lib/when_exe/locales/ur.rb +84 -0
  35. data/lib/when_exe/mini_application.rb +44 -43
  36. data/lib/when_exe/parts/enumerator.rb +3 -3
  37. data/lib/when_exe/parts/geometric_complex.rb +6 -1
  38. data/lib/when_exe/parts/locale.rb +49 -18
  39. data/lib/when_exe/parts/method_cash.rb +61 -0
  40. data/lib/when_exe/parts/resource.rb +221 -106
  41. data/lib/when_exe/parts/timezone.rb +70 -33
  42. data/lib/when_exe/region/bahai.rb +2 -2
  43. data/lib/when_exe/region/balinese.rb +40 -43
  44. data/lib/when_exe/region/chinese.rb +93 -33
  45. data/lib/when_exe/region/chinese_calendar.rb +117 -1
  46. data/lib/when_exe/region/chinese_epoch.rb +65 -10
  47. data/lib/when_exe/region/christian.rb +97 -2
  48. data/lib/when_exe/region/ephemeric_notes.rb +353 -0
  49. data/lib/when_exe/region/french.rb +1 -1
  50. data/lib/when_exe/region/geologicalage.rb +171 -171
  51. data/lib/when_exe/region/indian.rb +18 -14
  52. data/lib/when_exe/region/iranian.rb +1 -1
  53. data/lib/when_exe/region/japanese.rb +49 -12
  54. data/lib/when_exe/region/japanese_notes.rb +838 -507
  55. data/lib/when_exe/region/japanese_residues.rb +724 -662
  56. data/lib/when_exe/region/javanese.rb +7 -7
  57. data/lib/when_exe/region/mayan.rb +19 -17
  58. data/lib/when_exe/region/nihon_shoki.rb +3 -3
  59. data/lib/when_exe/region/residue.rb +29 -28
  60. data/lib/when_exe/region/shire.rb +2 -2
  61. data/lib/when_exe/region/tibetan.rb +87 -5
  62. data/lib/when_exe/region/world.rb +1 -1
  63. data/lib/when_exe/timestandard.rb +85 -7
  64. data/lib/when_exe/tmobjects.rb +32 -4
  65. data/lib/when_exe/tmposition.rb +104 -55
  66. data/lib/when_exe/tmreference.rb +157 -60
  67. data/lib/when_exe/version.rb +2 -2
  68. data/test/examples/JapanHolidays.ics +3 -3
  69. data/test/examples/JapanHolidaysRFC6350.ics +499 -0
  70. data/test/examples/Residue.m17n +3 -2
  71. data/test/examples/Spatial.m17n +3 -3
  72. data/test/examples/USA-DST.ics +27 -27
  73. data/test/examples/today.rb +1 -1
  74. data/test/test.rb +4 -2
  75. data/test/test/basictypes.rb +40 -15
  76. data/test/test/coordinates.rb +9 -4
  77. data/test/test/icalendar.rb +24 -14
  78. data/test/test/inspect.rb +5 -3
  79. data/test/test/parts.rb +11 -2
  80. data/test/test/region/chinese.rb +4 -4
  81. data/test/test/region/civil.rb +124 -0
  82. data/test/test/region/geologicalage.rb +5 -2
  83. data/test/test/region/indian.rb +2 -0
  84. data/test/test/region/japanese.rb +156 -1
  85. data/test/test/region/jewish.rb +3 -3
  86. data/test/test/region/m17n.rb +9 -9
  87. data/test/test/region/mayan.rb +122 -5
  88. data/test/test/region/residue.rb +1 -1
  89. data/test/test/tmobjects.rb +27 -64
  90. data/test/test/tmposition.rb +48 -1
  91. data/test/test/tmreference.rb +66 -4
  92. data/when_exe.gemspec +1 -1
  93. metadata +15 -6
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  =begin
3
- Copyright (C) 2011-2013 Takashi SUGA
3
+ Copyright (C) 2011-2014 Takashi SUGA
4
4
 
5
5
  You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
6
  =end
@@ -19,16 +19,33 @@ module When::Parts
19
19
  LabelProperty = nil
20
20
 
21
21
  # @private
22
- class Element
23
- attr_reader :predicate
24
- attr_reader :object
25
- attr_reader :attribute
22
+ class ContentLine
23
+
24
+ RFC6350 = {
25
+ "\\\\" => "\\",
26
+ "\\n" => "\n",
27
+ "\\N" => "\n",
28
+ "\\;" => ";",
29
+ "\\:" => ":"
30
+ }
31
+
32
+ RFC6868 = {
33
+ "^n" => "\n",
34
+ "^^" => "^",
35
+ "^'" => '"'
36
+ }
37
+
38
+ attr_reader :predicate
39
+ attr_accessor :object
40
+ attr_reader :attribute
26
41
  attr_accessor :namespace
27
- attr_reader :marked
42
+ attr_accessor :same_altid
43
+ attr_reader :marked
28
44
 
29
45
  def initialize(key, object=nil, marked=nil)
30
46
  key = key.downcase.gsub(/-/,'_') if (key==key.upcase)
31
47
  @predicate, @namespace = key.split(/:/).reverse
48
+ object = object.gsub(/\^./) {|escape| RFC6868[escape] || escape} if object.instance_of?(String)
32
49
  @object = object
33
50
  @marked = marked
34
51
  @attribute = {}
@@ -80,21 +97,16 @@ module When::Parts
80
97
  #
81
98
  def [](label)
82
99
 
83
- # nil label
100
+ # nil label の場合
84
101
  return _pool[label] unless label
85
102
 
86
- # 階層構造の確認
87
- unless label =~ /\?/
88
- terms = label.split(/::/)
89
- terms.shift if terms[0] == ''
90
- return terms.inject(self) {|obj,term| obj = obj[term]} if terms.length >= 2
91
- end
103
+ # 階層がある場合
104
+ terms = Resource._encode(label).split(/::/)
105
+ terms.shift if terms[0] == ''
106
+ return terms.inject(self) {|obj,term| obj = obj[Resource._decode(term)]} if terms.length >= 2
92
107
 
93
108
  # 階層がない場合
94
- path, options = label.split(/\?/, 2)
95
- label = Resource._extract_prefix(path)
96
- label += '?' + options if options
97
- _pool[label.gsub(/%3A%3A/, '::')]
109
+ _pool[Resource._decode(Resource._extract_prefix(terms[0]))]
98
110
  end
99
111
 
100
112
  # オブジェクト登録
@@ -192,13 +204,17 @@ module When::Parts
192
204
  return iri unless iri.instance_of?(String)
193
205
 
194
206
  # 階層がある場合は、階層をたどる
207
+ iri = Resource._decode(iri)
208
+ iri = $1 while iri =~ /^\((.*)\)$/
195
209
  iri = namespace + iri if namespace && iri !~ /^[_a-z\d]+:[^:]/i
196
- root, *leaves= iri.split(/::/)
197
- return leaves.inject(_instance(root)) {|obj,leaf| obj[leaf]} unless leaves==[] || iri =~ /\?/
210
+ root, *leaves= Resource._encode(iri).split(/::/)
211
+ if leaves.size > 0
212
+ return leaves.inject(_instance(Resource._decode(root))) {|obj,leaf| obj[Resource._decode(leaf)]}
213
+ end
198
214
 
199
215
  # 登録ずみなら、参照
200
- path, query = _extract_prefix(iri).split(/\?/, 2)
201
- iri = query ? (path + '?' + query) : path
216
+ iri = _extract_prefix(iri)
217
+ path, query = iri.split(/\?/, 2)
202
218
  if When.multi_thread
203
219
  my_mutex = nil
204
220
  @_lock_.synchronize do
@@ -236,21 +252,26 @@ module When::Parts
236
252
  def _parse(line, type=nil)
237
253
  return line unless line.kind_of?(String)
238
254
  line.sub!(/\s#.*$/, '')
239
- return Locale._split($1) if type && line =~ /^#{type}:(.+)$/i
240
- return Locale._split(line) unless line =~ /^(\*)?([A-Z][-A-Z_]{0,255})(?:;(.*?))?:(.*)$/i
241
-
242
- marked, key, property, value = $~[1..4]
243
- element = Element.new(key, value, marked)
244
- if (property)
245
- element.attribute['.'] = property+':'+value
246
- property.split(/;/) do |pr|
247
- prop = Element.new(*pr.split(/=/, 2))
248
- element.attribute[prop.predicate] = prop
255
+ return Locale._split($1) if type && /^#{type}:(.+)$/i =~ line
256
+ tokens = line.scan(/((?:[^\\:]|\\.)+)(?::(?!\z))?|:/).flatten
257
+ return Locale._split(line) unless tokens.size > 1 && /^(\*)?([A-Z][-A-Z_]{0,255})(?:;(.+))?$/i =~ tokens[0]
258
+ marked, key, property = $~[1..3]
259
+ values = tokens[1..-1]
260
+ value = values.join(':') unless values == [nil]
261
+ content = ContentLine.new(key, value, marked)
262
+ value ||= ''
263
+ if property
264
+ content.attribute['.'] = property + ':' + value
265
+ property.scan(/((?:[^\\;]|\\.)+)(?:;(?!\z))?|;/).flatten.each do |pr|
266
+ pr ||= ''
267
+ pr.gsub!(/\\./) {|escape| ContentLine::RFC6350[escape] || escape}
268
+ prop = ContentLine.new(*pr.split(/=/, 2))
269
+ content.attribute[prop.predicate] = prop
249
270
  end
250
271
  else
251
- element.attribute['.'] = value
272
+ content.attribute['.'] = value
252
273
  end
253
- return element
274
+ return content
254
275
  end
255
276
 
256
277
  # @private
@@ -270,16 +291,72 @@ module When::Parts
270
291
  return path
271
292
  end
272
293
 
294
+ # @private
295
+ def _replace_tags(source, tags)
296
+ case source
297
+ when String
298
+ target = source.dup
299
+ tags.each_pair do |key, value|
300
+ target.gsub!(/#\{(\?[^=#}]+?=)?#{key}(:.*?)?\}/, '\1' + value) if value.kind_of?(String)
301
+ end
302
+ target.gsub(/#\{.+?(:(.*?))?\}/, '\2')
303
+ when Array
304
+ source.map {|target| _replace_tags(target, tags)}
305
+ when Hash
306
+ target = {}
307
+ source.each_pair do |key, value|
308
+ target[key] = tags[key].kind_of?(Numeric) ? tags[key] : _replace_tags(value, tags)
309
+ end
310
+ target
311
+ else
312
+ source
313
+ end
314
+ end
315
+
316
+ # @private
317
+ def _encode(iri)
318
+ return iri unless iri =~ /\(/
319
+
320
+ iri = iri.dup
321
+ begin
322
+ unless iri.gsub!(/\([^()]*\)/) {|token|
323
+ token.gsub(/[():?&%]/) {|char|'%' + char.ord.to_s(16)}
324
+ }
325
+ raise ArgumentError, 'Brackets do not correspond: ' + iri
326
+ end
327
+ end while iri =~ /\(/
328
+ iri
329
+ end
330
+
331
+ # @private
332
+ def _decode(iri)
333
+ return iri unless iri =~ /%28/
334
+
335
+ iri = iri.dup
336
+ begin
337
+ unless iri.gsub!(/%28.*?%29/) {|token|
338
+ token.gsub(/%([\dA-F]{2})/i) {$1.to_i(16).chr}
339
+ }
340
+ raise ArgumentError, 'Brackets do not correspond: ' + iri
341
+ end
342
+ end while iri =~ /%28/
343
+ iri = $1 if iri =~ /^\((.*)\)$/
344
+ iri
345
+ end
346
+
273
347
  private
274
348
 
275
349
  def _create_object(iri, path, query)
276
350
  options = {}
277
351
  replace = {}
278
352
  if query
279
- options = Hash[*query.split(/&/).map{ |pair| pair.split(/=/, 2) }.flatten]
353
+ options = Hash[*Resource._encode(query).split(/&/).map{|pair|
354
+ key, value = pair.split(/=/, 2)
355
+ [key, Resource._decode(value)]
356
+ }.flatten]
280
357
  keys = options.keys
281
358
  keys.each do |key|
282
- replace[$1] = options.delete(key) if key =~ /^!(.+)/
359
+ replace[$1] = options.delete(key) if key =~ /^([A-Z].*)/
283
360
  end
284
361
  end
285
362
  options['..'] = iri
@@ -292,6 +369,14 @@ module When::Parts
292
369
  when Class
293
370
  obj = list[0].new(options)
294
371
  when Array
372
+ top = list[0][0]
373
+ if top.kind_of?(Hash)
374
+ top.each_pair do |key, value|
375
+ replace.update(value[replace.delete(key)]) if value.kind_of?(Hash) && value.key?(replace[key])
376
+ end
377
+ list[0] = list[0][1..-1]
378
+ list[0] = _replace_tags(list[0], top.merge(replace))
379
+ end
295
380
  if list[0][0].kind_of?(Class)
296
381
  # 配列の先頭がクラスである場合
297
382
  klass, *list = list[0]
@@ -317,11 +402,10 @@ module When::Parts
317
402
  parsed = nil
318
403
  OpenURI
319
404
  begin
320
- open(path, "1".respond_to?(:force_encoding) ? 'r:utf-8' : 'r') do |file|
321
- resource = file.read
322
- replace.keys.each do |key|
323
- resource.gsub!(/#\{#{key}\}/, replace[key])
324
- end
405
+ args = [path, "1".respond_to?(:force_encoding) ? 'r:utf-8' : 'r']
406
+ args << {:ssl_verify_mode=>OpenSSL::SSL::VERIFY_NONE} if path =~ /^https:/
407
+ open(*args) do |file|
408
+ resource = _replace_tags(file.read, replace)
325
409
  parsed = (resource[0..5]=='BEGIN:') ? _ics(resource.split(/[\n\r]+/)) :
326
410
  _xml(REXML::Document.new(resource).root)
327
411
  end
@@ -339,9 +423,9 @@ module When::Parts
339
423
  end
340
424
 
341
425
  def _class(path)
342
- return nil unless (path =~ /^http:\/\/hosi\.org\/When\/(.*)/)
343
- list = [When]
344
- $1.split(/\//).each do |mod|
426
+ return nil unless path.index(Resource.base_uri) == 0
427
+ list = [When]
428
+ path[Resource.base_uri.length..-1].split(/\//).each do |mod|
345
429
  if list[0].const_defined?(mod)
346
430
  list.unshift(list[0].const_get(mod))
347
431
  else
@@ -362,19 +446,19 @@ module When::Parts
362
446
  key = '' if expanded_name == 'xmlns'
363
447
  namespace[key] = value.to_s
364
448
  end
365
- obj << Element.new('xmlns:namespace', namespace) if (namespace.size>0)
449
+ obj << ContentLine.new('xmlns:namespace', namespace) if (namespace.size>0)
366
450
  xml.each do |e|
367
451
  next unless defined? e.name
368
452
  if (e.attributes['type'])
369
453
  obj << _xml(e, namespace)
370
454
  else
371
- element = Element.new(e.expanded_name, e.attributes['ref']||e.text)
455
+ content = ContentLine.new(e.expanded_name, e.attributes['ref']||e.text)
372
456
  e.attributes.each_pair do |key,value|
373
- attr = Element.new(value.name, value)
457
+ attr = ContentLine.new(value.name, value)
374
458
  attr.namespace = value.prefix
375
- element.attribute[key] = attr
459
+ content.attribute[key] = attr
376
460
  end
377
- obj << element
461
+ obj << content
378
462
  end
379
463
  end
380
464
  return obj
@@ -461,7 +545,6 @@ module When::Parts
461
545
  return @iri if @iri
462
546
  root = @_pool['..']
463
547
  path = root.instance_of?(String) ? root : label.to_s
464
- path = path.gsub(/::/, '%3A%3A')
465
548
  if root.respond_to?(:iri)
466
549
  prefix = root.iri
467
550
  path = prefix + '::' + path if prefix
@@ -482,15 +565,15 @@ module When::Parts
482
565
  return child[iri * 1]
483
566
  when String
484
567
  obj = self
485
- iri.split(/::/).each do |label|
568
+ Resource._encode(iri).split(/::/).each do |label|
486
569
  return obj.child if label == '*'
487
570
  if obj == Resource
488
- obj = Resource._instance(label)
571
+ obj = Resource._instance(Resource._decode(label))
489
572
  else
490
573
  case label
491
574
  when '' ; obj = Resource
492
575
  when '.' # obj = obj
493
- else ; obj = obj._pool[label.gsub(/%3A%3A/, '::')]
576
+ else ; obj = obj._pool[Resource._decode(label)]
494
577
  end
495
578
  end
496
579
  raise ArgumentError, "IRI not found: #{iri}" unless obj
@@ -703,13 +786,7 @@ module When::Parts
703
786
  def _set_variables(options)
704
787
  @options = options[:options] || {} if options.key?(:options)
705
788
  options.each_pair do |key,value|
706
- unless (key =~ /^options$|^[_.]/)
707
- # スキームの":"がエンコーディングされていたら、valueをデコード
708
- if (value =~ /^\w+%3A/i)
709
- value.gsub!(/%[0-9A-F]{2}/i) do |c|
710
- c.sub(/%/,'0x').hex.chr
711
- end
712
- end
789
+ unless (key =~ /^options$|^\.|^[A-Z]/)
713
790
  case "#{key}"
714
791
  when 'namespace' ; value = Locale._namespace(value)
715
792
  when 'locale' ; value = Locale._locale(value)
@@ -721,67 +798,97 @@ module When::Parts
721
798
 
722
799
  # 配下のオブジェクトの生成
723
800
  def _child(options)
724
- @child = []
725
- query = options.dup
726
- options['..'] = self
727
- leaf = options['.']
801
+ @child = []
802
+ query = options.dup
803
+ options['..'] = self
804
+ leaves = options.delete('.').map {|leaf| Resource._parse(leaf)}
805
+ key_list = []
806
+ properties = {}
728
807
  label_candidates = nil
729
808
 
730
- leaf.each_index do |i|
731
- element = Resource._parse(leaf[i])
732
- case element
733
- when Array
734
- if element[0].kind_of?(Class)
735
- list = []
736
- element.each do |e|
737
- if e.kind_of?(Hash)
738
- list += e.keys.map {|key| Resource::Element.new(key, e[key])}
739
- else
740
- list << e
741
- end
742
- end
743
- options['.'] = list
744
- @child << element[0].new(options.dup)
809
+ # ContentLine の処理(namespace, locale, altidの前処理)
810
+ leaves.each do |content|
811
+ next unless content.kind_of?(ContentLine)
812
+ key = content.predicate
813
+ value = content.object
814
+ next options.delete(key) unless value
815
+ case key
816
+ when 'namespace'
817
+ options[key] ||= {}
818
+ if content.attribute['altid']
819
+ options[key][content.attribute['prefix'].object] = content.object
745
820
  else
746
- options.delete('.')
747
- @child << self.class.new(*(element + [options]))
821
+ options[key] = options[key].update(Locale._namespace(value))
748
822
  end
823
+ when 'locale'
824
+ options[key] = Locale._locale(value)
825
+ else
826
+ _parse_altid(properties, content)
827
+ key_list << key unless key_list.include?(key)
828
+ end
829
+ end
749
830
 
750
- when Resource::Element
751
- key = element.predicate
752
- value = element.object
753
- if (value)
754
- case key
755
- when 'namespace'
756
- options[key] ||= {}
757
- options[key] = options[key].merge(Locale._namespace(value))
758
- when 'locale'
759
- options[key] = Locale._locale(value)
831
+ # ContentLine の処理(一般)
832
+ key_list.each do |key|
833
+ content = properties[key][0]
834
+ value = content.same_altid ? When::BasicTypes::M17n.new(content, options['namespace'], []) : content.object
835
+ value = When::BasicTypes::M17n.new(value, nil, nil, options) if value.instance_of?(String) && value =~ /^\s*\[/
836
+ @_pool[value.to_s] = value if value.kind_of?(When::BasicTypes::M17n)
837
+ if content.marked || key == self.class::LabelProperty
838
+ @label = value
839
+ else
840
+ options[key] = value
841
+ label_candidates ||= value
842
+ end
843
+ end
844
+
845
+ # Array の処理(子オブジェクトの生成)
846
+ leaves.each do |content|
847
+ next unless content.kind_of?(Array)
848
+ if content[0].kind_of?(Class)
849
+ list = []
850
+ content.each do |e|
851
+ if e.kind_of?(Hash)
852
+ list += e.keys.map {|key| Resource::ContentLine.new(key, e[key])}
760
853
  else
761
- if (value.instance_of?(String) && value =~ /^\[/)
762
- options.delete('.')
763
- value = m17n(value, nil, nil, options.dup)
764
- @_pool[value.to_s] = value
765
- end
766
- if element.marked || key == self.class::LabelProperty
767
- @label = value
768
- else
769
- options[key] = value
770
- label_candidates ||= value
771
- end
854
+ list << e
772
855
  end
773
- else
774
- options.delete(key)
775
856
  end
857
+ options['.'] = list
858
+ @child << content[0].new(options.dup)
859
+ else
860
+ options.delete('.')
861
+ @child << self.class.new(*(content + [options]))
776
862
  end
777
863
  end
864
+
865
+ # 代表ラベルの設定
778
866
  options.update(query)
779
867
  unless @label
780
- raise ArgumentError, "label attribute not found: #{leaf}" unless label_candidates
868
+ raise ArgumentError, "label attribute not found: #{options['.']}" unless label_candidates
781
869
  @label = label_candidates
782
870
  end
783
871
  end
784
872
 
873
+ # ALTIDを持つ ContentLine の解析
874
+ def _parse_altid(properties, content)
875
+ key = content.predicate
876
+ properties[key] ||= []
877
+ if content.attribute['altid']
878
+ found = false
879
+ (0...properties[key].length).to_a.each do |i|
880
+ prev = properties[key][i]
881
+ if prev.attribute['altid'] && prev.attribute['altid'].object == content.attribute['altid'].object
882
+ content.same_altid = prev
883
+ properties[key][i] = content
884
+ found = true
885
+ break
886
+ end
887
+ end
888
+ end
889
+ properties[key] << content unless found
890
+ end
891
+
785
892
  # 配下のオブジェクトの前後関係の設定
786
893
  def _sequence
787
894
  return unless @child
@@ -800,12 +907,20 @@ module When::Parts
800
907
  end
801
908
  end
802
909
 
910
+ alias :__method_missing :method_missing
911
+
803
912
  # その他のメソッド
804
- # When::Parts::GeometricComplex で定義されていないメソッドは
913
+ # When::Parts::Resource で定義されていないメソッドは
805
914
  # 処理を @child (type: Array) に委譲する
806
915
  #
807
916
  def method_missing(name, *args, &block)
808
- @child.send(name.to_sym, *args, &block)
917
+ return __method_missing(name, *args, &block) if When::Parts::MethodCash::Escape.key?(name)
918
+ self.class.module_eval %Q{
919
+ def #{name}(*args, &block)
920
+ @child.send("#{name}", *args, &block)
921
+ end
922
+ } unless When::Parts::MethodCash.escape(name)
923
+ @child.send(name, *args, &block)
809
924
  end
810
925
 
811
926
  #