when_exe 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,307 +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 =~ /\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
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2013-2015 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_go_back}) || -1]]
248
+ else
249
+ eras.delete_if {|e| e.calendar_era_go_back}
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