when_exe 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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