when_exe 0.3.6 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +171 -0
  3. data/lib/when_exe.rb +78 -47
  4. data/lib/when_exe/basictypes.rb +752 -747
  5. data/lib/when_exe/calendarnote.rb +805 -801
  6. data/lib/when_exe/calendartypes.rb +1583 -1531
  7. data/lib/when_exe/coordinates.rb +16 -15
  8. data/lib/when_exe/core/duration.rb +114 -110
  9. data/lib/when_exe/core/extension.rb +504 -504
  10. data/lib/when_exe/ephemeris.rb +1917 -1913
  11. data/lib/when_exe/ephemeris/moon.rb +333 -333
  12. data/lib/when_exe/ephemeris/notes.rb +389 -387
  13. data/lib/when_exe/ephemeris/planets.rb +585 -585
  14. data/lib/when_exe/ephemeris/sun.rb +214 -214
  15. data/lib/when_exe/googlecalendar.rb +144 -140
  16. data/lib/when_exe/icalendar.rb +1636 -1636
  17. data/lib/when_exe/inspect.rb +46 -22
  18. data/lib/when_exe/locales/akt.rb +176 -176
  19. data/lib/when_exe/locales/encoding_conversion.rb +134 -126
  20. data/lib/when_exe/locales/iast.rb +90 -90
  21. data/lib/when_exe/locales/locale.rb +750 -746
  22. data/lib/when_exe/locales/transliteration_table.rb +62 -62
  23. data/lib/when_exe/mini_application.rb +307 -305
  24. data/lib/when_exe/parts/enumerator.rb +2 -2
  25. data/lib/when_exe/parts/geometric_complex.rb +397 -397
  26. data/lib/when_exe/parts/method_cash.rb +224 -224
  27. data/lib/when_exe/parts/resource.rb +1069 -1071
  28. data/lib/when_exe/parts/timezone.rb +240 -230
  29. data/lib/when_exe/region/armenian.rb +56 -56
  30. data/lib/when_exe/region/babylonian.rb +405 -0
  31. data/lib/when_exe/region/bahai.rb +146 -146
  32. data/lib/when_exe/region/balinese.rb +622 -622
  33. data/lib/when_exe/region/chinese.rb +95 -25
  34. data/lib/when_exe/region/chinese/calendars.rb +1016 -1016
  35. data/lib/when_exe/region/chinese/epochs.rb +1 -1
  36. data/lib/when_exe/region/chinese/twins.rb +803 -795
  37. data/lib/when_exe/region/christian.rb +824 -824
  38. data/lib/when_exe/region/coptic.rb +106 -87
  39. data/lib/when_exe/region/discordian.rb +225 -225
  40. data/lib/when_exe/region/far_east.rb +188 -188
  41. data/lib/when_exe/region/french.rb +56 -56
  42. data/lib/when_exe/region/geologicalage.rb +639 -639
  43. data/lib/when_exe/region/goddess.rb +58 -58
  44. data/lib/when_exe/region/indian.rb +1254 -1251
  45. data/lib/when_exe/region/iranian.rb +8 -8
  46. data/lib/when_exe/region/islamic.rb +3 -3
  47. data/lib/when_exe/region/japanese.rb +93 -99
  48. data/lib/when_exe/region/japanese/calendars.rb +396 -397
  49. data/lib/when_exe/region/japanese/epochs.rb +26 -26
  50. data/lib/when_exe/region/japanese/nihon_shoki.rb +71 -71
  51. data/lib/when_exe/region/japanese/notes.rb +1383 -1386
  52. data/lib/when_exe/region/japanese/residues.rb +1306 -1306
  53. data/lib/when_exe/region/japanese/twins.rb +225 -225
  54. data/lib/when_exe/region/japanese/weeks.rb +112 -0
  55. data/lib/when_exe/region/javanese.rb +230 -230
  56. data/lib/when_exe/region/jewish.rb +126 -126
  57. data/lib/when_exe/region/korean.rb +378 -378
  58. data/lib/when_exe/region/m17n.rb +114 -113
  59. data/lib/when_exe/region/martian.rb +258 -255
  60. data/lib/when_exe/region/mayan.rb +32 -32
  61. data/lib/when_exe/region/residue.rb +89 -89
  62. data/lib/when_exe/region/roman.rb +36 -24
  63. data/lib/when_exe/region/ryukyu.rb +97 -97
  64. data/lib/when_exe/region/shire.rb +240 -240
  65. data/lib/when_exe/region/soviet.rb +209 -0
  66. data/lib/when_exe/region/symmetry.rb +50 -50
  67. data/lib/when_exe/region/thai.rb +336 -335
  68. data/lib/when_exe/region/tibetan.rb +316 -315
  69. data/lib/when_exe/region/vietnamese.rb +440 -439
  70. data/lib/when_exe/region/weekdate.rb +80 -80
  71. data/lib/when_exe/region/world.rb +175 -175
  72. data/lib/when_exe/region/yerm.rb +14 -14
  73. data/lib/when_exe/region/zoroastrian.rb +203 -203
  74. data/lib/when_exe/timestandard.rb +707 -681
  75. data/lib/when_exe/tmduration.rb +338 -330
  76. data/lib/when_exe/tmobjects.rb +1346 -1325
  77. data/lib/when_exe/tmposition.rb +2115 -2072
  78. data/lib/when_exe/tmreference.rb +1693 -1669
  79. data/lib/when_exe/version.rb +1 -1
  80. data/link_to_online_documents +1 -1
  81. data/test/examples/JapanHolidaysRFC6350.ics +1 -1
  82. data/test/test.rb +67 -61
  83. data/test/test/basictypes.rb +409 -409
  84. data/test/test/calendarnote.rb +86 -69
  85. data/test/test/calendartypes.rb +97 -97
  86. data/test/test/coordinates.rb +396 -396
  87. data/test/test/ephemeris.rb +83 -74
  88. data/test/test/ephemeris/moon.rb +14 -14
  89. data/test/test/ephemeris/planets.rb +14 -14
  90. data/test/test/ephemeris/sun.rb +14 -14
  91. data/test/test/googlecalendar.rb +194 -176
  92. data/test/test/icalendar.rb +867 -858
  93. data/test/test/inspect.rb +117 -117
  94. data/test/test/parts.rb +487 -487
  95. data/test/test/region/balinese.rb +34 -0
  96. data/test/test/region/chinese.rb +218 -206
  97. data/test/test/region/christian.rb +245 -245
  98. data/test/test/region/coptic.rb +27 -27
  99. data/test/test/region/french.rb +33 -33
  100. data/test/test/region/geologicalage.rb +17 -17
  101. data/test/test/region/indian.rb +57 -57
  102. data/test/test/region/iran.rb +54 -54
  103. data/test/test/region/islamic.rb +18 -18
  104. data/test/test/region/japanese.rb +237 -219
  105. data/test/test/region/jewish.rb +61 -61
  106. data/test/test/region/m17n.rb +184 -184
  107. data/test/test/region/mayan.rb +195 -195
  108. data/test/test/region/residue.rb +147 -139
  109. data/test/test/region/thai.rb +116 -116
  110. data/test/test/region/tibetan.rb +30 -30
  111. data/test/test/region/vietnamese.rb +102 -102
  112. data/test/test/region/yerm.rb +146 -146
  113. data/test/test/timestandard.rb +81 -81
  114. data/test/test/tmobjects.rb +328 -328
  115. data/test/test/tmposition.rb +397 -284
  116. data/test/test/tmreference.rb +157 -157
  117. metadata +13 -10
@@ -1,62 +1,62 @@
1
- # -*- coding: utf-8 -*-
2
- =begin
3
- Copyright (C) 2014 Takashi SUGA
4
-
5
- You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
- =end
7
-
8
- module When
9
- module Locale
10
- class << self
11
-
12
- #
13
- # Generate Regexp for transliteration
14
- #
15
- # @param [Hash] hash transliteration table
16
- #
17
- # @return [Regexp] Regexp for transliteration
18
- #
19
- def transliteration_keys(hash)
20
- Regexp.new((hash.keys.sort_by {|key| -key.length} + ['%.*?[A-Za-z]']).join('|'))
21
- end
22
-
23
- #
24
- # Generate Hash of {locale=>Regexp} for transliteration
25
- #
26
- # @param [Hash] hash transliteration table hash
27
- #
28
- # @return [Hash{String=>Regexp}] Hash of {locale=>Regexp} for transliteration
29
- #
30
- def transliteration_keys_hash(hash)
31
- Hash[*(hash.keys.map {|locale|
32
- [locale, transliteration_keys(hash[locale])]
33
- }).flatten]
34
- end
35
-
36
- alias :_method_missing :method_missing
37
-
38
- #
39
- # �ϊ����\�b�h�̓o�^
40
- #
41
- def method_missing(name, *args, &block)
42
- table_name = name.to_s.upcase
43
- return _method_missing(name, *args, &block) unless table_name !~ /_/ && const_defined?(table_name)
44
- table_obj = const_get(table_name)
45
- default = table_obj.keys.first
46
- locale = args[1] || default
47
- const_set(table_name + '_keys', transliteration_keys_hash(table_obj)) unless const_defined?(table_name + '_keys')
48
- return send(name, args[0], locale) if respond_to?(name)
49
- instance_eval %Q{
50
- def #{name}(string, locale='#{default}')
51
- string.gsub(#{table_name}_keys[locale]) do |code|
52
- #{table_name}[locale][code] || code
53
- end
54
- end
55
- }
56
- args[0].gsub(const_get("#{table_name}_keys")[locale]) do |code|
57
- table_obj[locale][code] || code
58
- end
59
- end
60
- end
61
- end
62
- end
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2014 Takashi SUGA
4
+
5
+ You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
+ =end
7
+
8
+ module When
9
+ module Locale
10
+ class << self
11
+
12
+ #
13
+ # Generate Regexp for transliteration
14
+ #
15
+ # @param [Hash] hash transliteration table
16
+ #
17
+ # @return [Regexp] Regexp for transliteration
18
+ #
19
+ def transliteration_keys(hash)
20
+ Regexp.new((hash.keys.sort_by {|key| -key.length} + ['%.*?[A-Za-z]']).join('|'))
21
+ end
22
+
23
+ #
24
+ # Generate Hash of {locale=>Regexp} for transliteration
25
+ #
26
+ # @param [Hash] hash transliteration table hash
27
+ #
28
+ # @return [Hash{String=>Regexp}] Hash of {locale=>Regexp} for transliteration
29
+ #
30
+ def transliteration_keys_hash(hash)
31
+ Hash[*(hash.keys.map {|locale|
32
+ [locale, transliteration_keys(hash[locale])]
33
+ }).flatten]
34
+ end
35
+
36
+ alias :_method_missing :method_missing
37
+
38
+ #
39
+ # �ϊ����\�b�h�̓o�^
40
+ #
41
+ def method_missing(name, *args, &block)
42
+ table_name = name.to_s.upcase
43
+ return _method_missing(name, *args, &block) unless table_name !~ /_/ && const_defined?(table_name)
44
+ table_obj = const_get(table_name)
45
+ default = table_obj.keys.first
46
+ locale = args[1] || default
47
+ const_set(table_name + '_keys', transliteration_keys_hash(table_obj)) unless const_defined?(table_name + '_keys')
48
+ return send(name, args[0], locale) if respond_to?(name)
49
+ instance_eval %Q{
50
+ def #{name}(string, locale='#{default}')
51
+ string.gsub(#{table_name}_keys[locale]) do |code|
52
+ #{table_name}[locale][code] || code
53
+ end
54
+ end
55
+ }
56
+ args[0].gsub(const_get("#{table_name}_keys")[locale]) do |code|
57
+ table_obj[locale][code] || code
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,305 +1,307 @@
1
- # -*- coding: utf-8 -*-
2
- =begin
3
- Copyright (C) 2013-2014 Takashi SUGA
4
-
5
- You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
- =end
7
-
8
- require 'socket'
9
-
10
- #
11
- # Time for v1.8.x compatibility
12
- #
13
- class Time
14
- if Time.now.respond_to?(:strftime) && Time.now.strftime('%FT%X.%L').length > 0
15
- alias :_log_ :strftime
16
- else
17
- def _log_(format)
18
- "%04d-%02d-%02dT%02d:%02d:%02d.%03d" % [year, month, day, hour, min, sec, usec / 1000]
19
- end
20
- end
21
- end
22
-
23
- #
24
- # Micro Client / Server
25
- #
26
- module When
27
- class << self
28
-
29
- #
30
- # 設定ファイルを読み込む
31
- # @private
32
- def config(path=File.expand_path($0) + '.config')
33
- config = {}
34
- open(path, 'r') do |file|
35
- while (line=file.gets)
36
- next if line =~ /^\s*#/
37
- key, *value = line.chomp.split(':')
38
- value = value[0] if value.size <= 1
39
- config[key] = value
40
- end
41
- end
42
- config
43
- rescue
44
- {}
45
- end
46
-
47
- #
48
- # マイクロ・サーバーを起動する
49
- #
50
- # @param [#to_i] port 待ち受けるポート番号
51
- #
52
- # @return [void]
53
- #
54
- # @note mini_application
55
- #
56
- def server(port)
57
- config = When.config
58
- TCPServer.open(port.to_i) do |socket|
59
- puts Time.now._log_('%FT%X.%L') + ': Start'
60
- loop do
61
- Thread.start(socket.accept) do |client|
62
- query = client.gets.chomp.force_encoding("UTF-8")
63
- start = Time.now
64
- puts start._log_('%FT%X.%L') + ': Query - ' + When::Locale.translate(query, config['!'])
65
- begin
66
- result = free_conv(*query.split(/\s+/))
67
- result = When::Locale.translate(result, config['!'])
68
- client.puts JSON.generate(Array(_to_string(result))).to_s
69
- stop = Time.now
70
- puts stop._log_('%FT%X.%L') + ": Respond (%7.0f ms)" % (1000 * (stop.to_f - start.to_f))
71
- rescue => err
72
- puts Time.now._log_('%FT%X.%L') + ': error - ' + err.to_s
73
- client.puts JSON.generate({:error=>query}).to_s
74
- end
75
- client.close
76
- end
77
- end
78
- end
79
- rescue Exception => e
80
- puts Time.now._log_('%FT%X.%L') + ': Exception - ' + e.to_s
81
- ensure
82
- puts Time.now._log_('%FT%X.%L') + ': Done.'
83
- end
84
-
85
- #
86
- # マイクロ・クライアントを実行する
87
- #
88
- # @param [String] server マイクロ・サーバのアドレス
89
- # @param [#to_i] port つなぐポート番号
90
- # @param [String] query 問い合わせ文字列
91
- #
92
- # @return [JSON] 応答
93
- #
94
- # @note mini_application
95
- #
96
- def client(server, port, query)
97
- TCPSocket.open(server, port.to_i) do |socket|
98
- socket.puts(query)
99
- results = JSON.parse(socket.gets.force_encoding("UTF-8"))
100
- results = Hash[*results.flatten(1)] if results[0].kind_of?(Array)
101
- _to_symbol(results)
102
- end
103
- end
104
-
105
- # 日付の自由変換
106
- #
107
- # @param [Array<String>] args コマンドライン入力
108
- # @param [Block] block ブロック
109
- #
110
- # @return [Array<Hash>] 変換結果
111
- # @return [Array<Array<Numeric>>] 最良近似分数列
112
- #
113
- # @note 暦法のIRI, When.exe Standard Expression, 最良近似分数列の分母分子などを文字列で指定
114
- # @note mini_application
115
- #
116
- def free_conv(*args, &block)
117
- calendars, dates, numbers, methods, output, options = _parse_command(args)
118
-
119
- if numbers.size >= 2 && calendars.size == 0
120
- result = []
121
- When::Coordinates::Residue.new(numbers[0], numbers[1]).each { |v| result << v }
122
- return result
123
- end
124
-
125
- block ||=
126
- if methods.size == 0
127
- lambda {|date| date.send(*output)}
128
- else
129
- lambda {|date, type| column(date, type)}
130
- end
131
- _free_conv(calendars, dates, methods, output, options, &block)
132
- end
133
-
134
- # 七曜表の一日分
135
- #
136
- # @param [When::TM::TemporalPosition] date 処理する一日
137
- # @param [Integer, nil] type 当該日の種類
138
- #
139
- # @return [Object>] 処理結果
140
- #
141
- def column(date, type)
142
- case type
143
- when When::YEAR ; date.strftime("%Y")
144
- when When::MONTH ; date.strftime("%B %Y")
145
- when When::WEEK ; nil
146
- when When::DAY ; date[0]
147
- else ; '-'
148
- end
149
- end
150
-
151
- private
152
-
153
- # to_h メソッドのオプション設定
154
- HashMethod = {:iri => [:to_h, {:method=>:iri , :prefix=>true}],
155
- :to_m17n => [:to_h, {:method=>:to_m17n, :prefix=>true}]}
156
-
157
- # 引数読み込み
158
- #
159
- # args [String] コマンドライン入力
160
- #
161
- # @return [Array] ( calendars, dates, numbers, methods )
162
- # [ calendars [Array<When::TM::Calendar or When::TM::CalendarEra>]]
163
- # [ dates [Array<When::TM::CalData or When::TM::DateAndTime>] ]
164
- # [ numbers [Array<Numeric>]]
165
- # [ methods [Array<String>] メソッド名('week', 'month', 'year') ]
166
- # [ output [Array<Symbol, String>] 出力処理に使うメソッドのシンボルと引数 ]
167
- # [ options [Hash{ :extent=>Boolean, :go_back=><:All || :Before(nil) || :After> }]
168
- #
169
- def _parse_command(args)
170
- calendars = []
171
- dates = []
172
- numbers = []
173
- methods = []
174
- options = {}
175
- output = [:to_s]
176
-
177
- config = When.config
178
- args.flatten.each do |arg|
179
- case arg
180
- when Numeric ; dates << arg ; numbers << arg
181
- when Hash ; options.update(arg)
182
- when Range ; arg.each {|d| dates << d}
183
- when Symbol ; output = [arg]
184
- when String
185
- arg = When::EncodingConversion.to_internal_encoding(arg)
186
- case arg
187
- when /^:(.+?)(?:\[(..)\])?$/ ; output = [$1.to_sym, $2].compact
188
- when /^(year|month|week)(?:\[(..)\])?$/i ; methods << [$1.downcase + '_included', $2||'SU']
189
- when /^[-+\d]\d*$/ ; dates << arg.to_i ; numbers << arg.to_i
190
- when /^[-+.\d][.\d]*$/ ; dates << arg.to_f ; numbers << arg.to_f
191
- when /^now$/i ; dates << When.now
192
- when /^today$/i ; dates << When.today
193
- when /(^[-+\d])|\^/ ; dates << arg
194
- when /^\//
195
- arg[1..-1].scan(/./) do |c|
196
- c = c.upcase
197
- if config.key?(c)
198
- calendar = config[c]
199
- calendar = calendar.join(':') if calendar.kind_of?(Array)
200
- calendars << When.Calendar(calendar)
201
- elsif c == 'D'
202
- calendars << When::TM::JulianDate
203
- end
204
- end
205
- else
206
- begin
207
- calendars << ((arg == 'JulianDate') ? When::TM::JulianDate : When.Calendar(arg))
208
- rescue NameError, OpenURI::HTTPError
209
- dates << arg
210
- end
211
- end
212
- else
213
- dates << arg
214
- end
215
- end
216
- [calendars, dates, numbers, methods, HashMethod[output[0]] || output, options]
217
- end
218
-
219
- # 変換処理(実行部)
220
- #
221
- # @param [When::TM::Calendar, When::TM::CalendarEra] calendars
222
- # @param [When::TM::CalData, When::TM::DateAndTime] dates
223
- # @param [String] methods メソッド名('week', 'month', 'year')
224
- # @param [Hash] options {:extent=>Boolean, :go_back=><:All||:Before(nil)||:After>}
225
- #
226
- # @return [Array] 変換結果
227
- #
228
- def _free_conv(calendars, dates, methods, output, options, &block)
229
- dates[0] ||= When.now
230
- calendars[0] ||= When::Gregorian
231
- result = dates.map {|date|
232
- date = When.when?(date)
233
- opts = {}
234
- opts[:location] = date.location if date.location
235
- opts[:clock ] = date.clock if date.respond_to?(:clock) && date.clock
236
- list = calendars.dup
237
- (0...calendars.size).to_a.reverse.each do |i|
238
- case list[i]
239
- when When::TM::Calendar ; list.slice!(i) if options[:extent] && !list[i].domain[''].include?(date)
240
- when Class ;
241
- else
242
- eras = (date ^ list[i]).delete_if {|e| !e.leaf?}
243
- unless options[:go_back] == :All
244
- if options[:go_back] == :After
245
- eras = [eras[(eras.index {|e| e.calendar_era_name[3]}) || -1]]
246
- else
247
- eras.delete_if {|e| e.calendar_era_name[3]}
248
- end
249
- end
250
- list[i,1] = eras.map {|e| e.calendar_era}
251
- end
252
- end
253
-
254
- if methods.size == 0
255
- list.map {|calendar|
256
- calendar.kind_of?(Class) ?
257
- yield(calendar.new(date, opts.dup)) :
258
- yield(calendar.^(calendar.rate_of_clock == date.time_standard.rate_of_clock ? date.to_i : date, opts))
259
- }
260
- else
261
- list.map {|calendar|
262
- date_for_calendar = calendar.^(calendar.rate_of_clock == date.time_standard.rate_of_clock ? date.to_i : date, opts)
263
- methods.map {|method|
264
- date_for_calendar.send(method[0].to_sym, method[1], &block)
265
- }
266
- }
267
- end
268
- }
269
- result = result[0] while result.kind_of?(Array) && result.size == 1
270
- return result
271
- end
272
-
273
- # JSONで通信するために Symbol を String に変換する
274
- def _to_string(source)
275
- case source
276
- when Array
277
- source.map {|e| _to_string(e)}
278
- when Hash
279
- result = {}
280
- source.each_pair {|k,v|
281
- result[k.kind_of?(Symbol) ? '_sym_' + k.to_s : k] = _to_string(v)
282
- }
283
- result
284
- else
285
- source
286
- end
287
- end
288
-
289
- # JSONで通信するために String を Symbol に変換する
290
- def _to_symbol(source)
291
- case source
292
- when Array
293
- source.map {|e| _to_symbol(e)}
294
- when Hash
295
- result = {}
296
- source.each_pair {|k,v|
297
- result[k =~ /^_sym_(.+)$/ ? $1.to_sym : k] = _to_symbol(v)
298
- }
299
- result
300
- else
301
- source
302
- end
303
- end
304
- end
305
- end
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2013-2014 Takashi SUGA
4
+
5
+ You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
+ =end
7
+
8
+ require 'socket'
9
+
10
+ #
11
+ # Time for v1.8.x compatibility
12
+ #
13
+ class Time
14
+ if Time.now.respond_to?(:strftime) && Time.now.strftime('%FT%X.%L').length > 0
15
+ alias :_log_ :strftime
16
+ else
17
+ def _log_(format)
18
+ "%04d-%02d-%02dT%02d:%02d:%02d.%03d" % [year, month, day, hour, min, sec, usec / 1000]
19
+ end
20
+ end
21
+ end
22
+
23
+ #
24
+ # Micro Client / Server
25
+ #
26
+ module When
27
+ class << self
28
+
29
+ #
30
+ # 設定ファイルを読み込む
31
+ # @private
32
+ def config(path=File.expand_path($0) + '.config')
33
+ config = {}
34
+ open(path, 'r') do |file|
35
+ while (line=file.gets)
36
+ next if line =~ /\A\s*#/
37
+ key, *value = line.chomp.split(':')
38
+ value = value[0] if value.size <= 1
39
+ config[key] = value
40
+ end
41
+ end
42
+ config
43
+ rescue
44
+ {}
45
+ end
46
+
47
+ #
48
+ # マイクロ・サーバーを起動する
49
+ #
50
+ # @param [#to_i] port 待ち受けるポート番号
51
+ #
52
+ # @return [void]
53
+ #
54
+ # @note mini_application
55
+ #
56
+ def server(port)
57
+ config = When.config
58
+ TCPServer.open(port.to_i) do |socket|
59
+ puts Time.now._log_('%FT%X.%L') + ': Start'
60
+ loop do
61
+ Thread.start(socket.accept) do |client|
62
+ query = client.gets.chomp.force_encoding("UTF-8")
63
+ start = Time.now
64
+ puts start._log_('%FT%X.%L') + ': Query - ' + When::Locale.translate(query, config['!'])
65
+ begin
66
+ result = free_conv(*query.split(/\s+/))
67
+ result = When::Locale.translate(result, config['!'])
68
+ client.puts JSON.generate(Array(_to_string(result))).to_s
69
+ stop = Time.now
70
+ puts stop._log_('%FT%X.%L') + ": Respond (%7.0f ms)" % (1000 * (stop.to_f - start.to_f))
71
+ rescue => err
72
+ puts Time.now._log_('%FT%X.%L') + ': error - ' + err.to_s
73
+ client.puts JSON.generate({:error=>query}).to_s
74
+ end
75
+ client.close
76
+ end
77
+ end
78
+ end
79
+ rescue Exception => e
80
+ puts Time.now._log_('%FT%X.%L') + ': Exception - ' + e.to_s
81
+ ensure
82
+ puts Time.now._log_('%FT%X.%L') + ': Done.'
83
+ end
84
+
85
+ #
86
+ # マイクロ・クライアントを実行する
87
+ #
88
+ # @param [String] server マイクロ・サーバのアドレス
89
+ # @param [#to_i] port つなぐポート番号
90
+ # @param [String] query 問い合わせ文字列
91
+ #
92
+ # @return [JSON] 応答
93
+ #
94
+ # @note mini_application
95
+ #
96
+ def client(server, port, query)
97
+ TCPSocket.open(server, port.to_i) do |socket|
98
+ socket.puts(query)
99
+ results = JSON.parse(socket.gets.force_encoding("UTF-8"))
100
+ results = Hash[*results.flatten(1)] if results[0].kind_of?(Array)
101
+ _to_symbol(results)
102
+ end
103
+ end
104
+
105
+ # 日付の自由変換
106
+ #
107
+ # @param [Array<String, When::TM::TemporalPosition, When::TM::CalendarEra or When::TM::Calendar>] args コマンドライン入力
108
+ # @param [Block] block ブロック
109
+ #
110
+ # @return [Array<Hash>] 変換結果
111
+ # @return [Array<Array<Numeric>>] 最良近似分数列
112
+ #
113
+ # @note 暦法のIRI, When.exe Standard Expression, 最良近似分数列の分母分子などを文字列で指定
114
+ # @note mini_application
115
+ #
116
+ def free_conv(*args, &block)
117
+ calendars, dates, numbers, methods, output, options = _parse_command(args)
118
+
119
+ if numbers.size >= 2 && calendars.size == 0
120
+ result = []
121
+ When::Coordinates::Residue.new(numbers[0], numbers[1]).each { |v| result << v }
122
+ return result
123
+ end
124
+
125
+ block ||=
126
+ if methods.size == 0
127
+ lambda {|date| date.send(*output)}
128
+ else
129
+ lambda {|date, type| column(date, type)}
130
+ end
131
+ _free_conv(calendars, dates, methods, output, options, &block)
132
+ end
133
+
134
+ # 七曜表の一日分
135
+ #
136
+ # @param [When::TM::TemporalPosition] date 処理する一日
137
+ # @param [Integer, nil] type 当該日の種類
138
+ #
139
+ # @return [Object>] 処理結果
140
+ #
141
+ def column(date, type)
142
+ case type
143
+ when When::YEAR ; date.strftime("%Y")
144
+ when When::MONTH ; date.strftime("%B %Y")
145
+ when When::WEEK ; nil
146
+ when When::DAY ; date[0]
147
+ else ; '-'
148
+ end
149
+ end
150
+
151
+ private
152
+
153
+ # to_h メソッドのオプション設定
154
+ HashMethod = {:iri => [:to_h, {:method=>:iri , :prefix=>true}],
155
+ :to_m17n => [:to_h, {:method=>:to_m17n, :prefix=>true}]}
156
+
157
+ # 引数読み込み
158
+ #
159
+ # args [String] コマンドライン入力
160
+ #
161
+ # @return [Array] ( calendars, dates, numbers, methods )
162
+ # [ calendars [Array<When::TM::Calendar or When::TM::CalendarEra>]]
163
+ # [ dates [Array<When::TM::CalData or When::TM::DateAndTime>] ]
164
+ # [ numbers [Array<Numeric>]]
165
+ # [ methods [Array<String>] メソッド名('week', 'month', 'year') ]
166
+ # [ output [Array<Symbol, String>] 出力処理に使うメソッドのシンボルと引数 ]
167
+ # [ options [Hash{ :extent=>Boolean, :go_back=><:All || :Before(nil) || :After> }]
168
+ #
169
+ def _parse_command(args)
170
+ calendars = []
171
+ dates = []
172
+ numbers = []
173
+ methods = []
174
+ options = {}
175
+ output = [:to_s]
176
+
177
+ config = When.config
178
+ args.flatten.each do |arg|
179
+ case arg
180
+ when Numeric ; dates << arg ; numbers << arg
181
+ when Hash ; options.update(arg)
182
+ when Range ; arg.each {|d| dates << d}
183
+ when Symbol ; output = [arg]
184
+ when When::TM::CalendarEra,
185
+ When::TM::Calendar ; calendars << arg
186
+ when String
187
+ arg = When::EncodingConversion.to_internal_encoding(arg)
188
+ case arg
189
+ when /\A:(.+?)(?:\[(..)\])?\z/ ; output = [$1.to_sym, $2].compact
190
+ when /\A(year|month|week)(?:\[(..)\])?\z/i ; methods << [$1.downcase + '_included', $2||'SU']
191
+ when /\A[-+\d]\d*\z/ ; dates << arg.to_i ; numbers << arg.to_i
192
+ when /\A[-+.\d][.\d]*\z/ ; dates << arg.to_f ; numbers << arg.to_f
193
+ when /\Anow\z/i ; dates << When.now
194
+ when /\Atoday\z/i ; dates << When.today
195
+ when /(^[-+\d])|\^/ ; dates << arg
196
+ when /\A\//
197
+ arg[1..-1].scan(/./) do |c|
198
+ c = c.upcase
199
+ if config.key?(c)
200
+ calendar = config[c]
201
+ calendar = calendar.join(':') if calendar.kind_of?(Array)
202
+ calendars << When.Calendar(calendar)
203
+ elsif c == 'D'
204
+ calendars << When::TM::JulianDate
205
+ end
206
+ end
207
+ else
208
+ begin
209
+ calendars << ((arg == 'JulianDate') ? When::TM::JulianDate : When.Calendar(arg))
210
+ rescue NameError, OpenURI::HTTPError
211
+ dates << arg
212
+ end
213
+ end
214
+ else
215
+ dates << arg
216
+ end
217
+ end
218
+ [calendars, dates, numbers, methods, HashMethod[output[0]] || output, options]
219
+ end
220
+
221
+ # 変換処理(実行部)
222
+ #
223
+ # @param [When::TM::Calendar, When::TM::CalendarEra] calendars
224
+ # @param [When::TM::CalData, When::TM::DateAndTime] dates
225
+ # @param [String] methods メソッド名('week', 'month', 'year')
226
+ # @param [Hash] options {:extent=>Boolean, :go_back=><:All||:Before(nil)||:After>}
227
+ #
228
+ # @return [Array] 変換結果
229
+ #
230
+ def _free_conv(calendars, dates, methods, output, options, &block)
231
+ dates[0] ||= When.now
232
+ calendars[0] ||= When::Gregorian
233
+ result = dates.map {|date|
234
+ date = When.when?(date)
235
+ opts = {}
236
+ opts[:location] = date.location if date.location
237
+ opts[:clock ] = date.clock if date.respond_to?(:clock) && date.clock
238
+ list = calendars.dup
239
+ (0...calendars.size).to_a.reverse.each do |i|
240
+ case list[i]
241
+ when When::TM::Calendar ; list.slice!(i) if options[:extent] && !list[i].domain[''].include?(date)
242
+ when Class ;
243
+ else
244
+ eras = (date ^ list[i]).delete_if {|e| !e.leaf?}
245
+ unless options[:go_back] == :All
246
+ if options[:go_back] == :After
247
+ eras = [eras[(eras.index {|e| e.calendar_era_name[3]}) || -1]]
248
+ else
249
+ eras.delete_if {|e| e.calendar_era_name[3]}
250
+ end
251
+ end
252
+ list[i,1] = eras.map {|e| e.calendar_era}
253
+ end
254
+ end
255
+
256
+ if methods.size == 0
257
+ list.map {|calendar|
258
+ calendar.kind_of?(Class) ?
259
+ yield(calendar.new(date, opts.dup)) :
260
+ yield(calendar.^(calendar.rate_of_clock == date.time_standard.rate_of_clock ? date.to_i : date, opts))
261
+ }
262
+ else
263
+ list.map {|calendar|
264
+ date_for_calendar = calendar.^(calendar.rate_of_clock == date.time_standard.rate_of_clock ? date.to_i : date, opts)
265
+ methods.map {|method|
266
+ date_for_calendar.send(method[0].to_sym, method[1], &block)
267
+ }
268
+ }
269
+ end
270
+ }
271
+ result = result[0] while result.kind_of?(Array) && result.size == 1
272
+ return result
273
+ end
274
+
275
+ # JSONで通信するために Symbol を String に変換する
276
+ def _to_string(source)
277
+ case source
278
+ when Array
279
+ source.map {|e| _to_string(e)}
280
+ when Hash
281
+ result = {}
282
+ source.each_pair {|k,v|
283
+ result[k.kind_of?(Symbol) ? '_sym_' + k.to_s : k] = _to_string(v)
284
+ }
285
+ result
286
+ else
287
+ source
288
+ end
289
+ end
290
+
291
+ # JSONで通信するために String を Symbol に変換する
292
+ def _to_symbol(source)
293
+ case source
294
+ when Array
295
+ source.map {|e| _to_symbol(e)}
296
+ when Hash
297
+ result = {}
298
+ source.each_pair {|k,v|
299
+ result[k =~ /\A_sym_(.+)\z/ ? $1.to_sym : k] = _to_symbol(v)
300
+ }
301
+ result
302
+ else
303
+ source
304
+ end
305
+ end
306
+ end
307
+ end