Class: Alone

Inherits:
Object
  • Object
show all
Defined in:
lib/al_main.rb

Overview

Note:

Aloneのベースとなる機能を、まとめている。

Aloneメインクラス

Defined Under Namespace

Classes: OutputTrap

Constant Summary

CHAR_ENT_REF =

escape_html用定数テーブル

{'<'=>'&lt;', '>'=>'&gt;', '&'=>'&amp;', '"'=>'&quot;', '\''=>'&#39;', "\r\n"=>'<br>', "\r"=>'<br>', "\n"=>'<br>' }
@@headers =

Httpヘッダ

Returns:

  • (Array)

    httpヘッダ

[ "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0" ]
@@cookies =

クッキー

Returns:

  • (Hash, NilClass)

    クッキー

nil
@@flag_redirect =

リダイレクトするかのフラグ

Returns:

  • (Boolean)

    リダイレクトするかのフラグ

false
@@flag_send_http_headers =

Httpヘッダを送ったかのフラグ

Returns:

  • (Boolean)

    httpヘッダを送ったかのフラグ

false
@@ctrl =

コントローラ名

Returns:

  • (String)

    コントローラ名

$2.to_s
@@action =

アクション名

Returns:

  • (String)

    アクション名

$2.to_s

Class Method Summary (collapse)

Class Method Details

+ (String) action

Getter アクション名

Returns:

  • (String)

    アクション名



54
55
56
# File 'lib/al_main.rb', line 54

def self.action()
  return @@action
end

+ (Object) add_http_header(header)

Note:

実際にhttpヘッダが送られる前に、使用する必要がある。 httpヘッダは、send_http_headers() メソッドで送られる。 典型的には、最初にユーザコードで文字列などが表示される直前に、 ヘッダが出力されるので、それまでに使用する。

httpヘッダの追加

Parameters:

  • (String) header

    ヘッダ文字列。“Tag: message.” 形式



165
166
167
# File 'lib/al_main.rb', line 165

def self.add_http_header( header )
  @@headers << header.chomp.gsub( /\r?\n[^ \t]|\r[^\n \t]/, ' ' )
end

+ (String) ctrl

Getter コントローラ名

Returns:

  • (String)

    コントローラ名



45
46
47
# File 'lib/al_main.rb', line 45

def self.ctrl()
  return @@ctrl
end

+ (String) decode_uri_component(s)

URIデコード

Parameters:

  • (String) s

    ソース文字列

Returns:

  • (String)

    デコード済み文字列



290
291
292
293
294
# File 'lib/al_main.rb', line 290

def self.decode_uri_component( s )
  a = s.gsub( /%([0-9a-fA-F]{2})/ ) { $1.hex.chr }
  a.force_encoding( AL_CHARSET )                # TODO: ruby1.9 only
      # TODO: UTF-8(あるいはその他の漢字コード)として無効なコードが来たらどうする?
end
Note:

httpヘッダに出力する関係上、ヘッダ出力前にコールする必要がある。

クッキーの消去

Parameters:

  • (String) name

    クッキー名

  • (String) path (defaults to: nil)

    パス



243
244
245
246
247
248
249
250
251
# File 'lib/al_main.rb', line 243

def self.delete_cookie( name, path = nil )
  # 既にヘッダへ出力予約されているものがあれば削除
  target = "Set-Cookie: #{name}="
  @@headers.delete_if { |h| h.start_with?( target ) }

  cookie = "Set-Cookie: #{name}=; expires=Thu, 08-Jun-1944 00:00:00 GMT"
  cookie << "; path=#{path}"  if path
  @@headers << cookie
end

+ (String) encode_uri_component(s)

URIエンコード

Parameters:

  • (String) s

    ソース文字列

Returns:

  • (String)

    エンコード済み文字列



277
278
279
280
281
# File 'lib/al_main.rb', line 277

def self.encode_uri_component( s )
  a = s.to_s.dup
  a.force_encoding( 'ASCII-8BIT' )            # TODO: ruby1.9 only
  a.gsub( /([^a-zA-Z0-9!'\(\)*\-._~])/ ) { "%#{$1.unpack('H2')[0]}" }
end

+ (String) escape_html(str)

html特殊文字のエスケープ

Parameters:

  • (String) str

    対象文字列

Returns:

  • (String)

    変換後文字列



348
349
350
# File 'lib/al_main.rb', line 348

def self.escape_html( str )
  return str.to_s.gsub( /([<>&"'])/ ) { CHAR_ENT_REF[$1] }
end

+ (String) escape_html_br(str)

Note:

html特殊文字のエスケープに加え、改行文字を
タグへ変更する。

html特殊文字のエスケープ with 改行文字

Parameters:

  • (String) str

    対象文字列

Returns:

  • (String)

    変換後文字列



361
362
363
# File 'lib/al_main.rb', line 361

def self.escape_html_br( str )
  return str.to_s.gsub( /([<>&"']|\r\n|\r|\n)/ ) { CHAR_ENT_REF[$1] }
end

クッキーの取得

Parameters:

  • (String, Symbol) name

    クッキー名

Returns:

  • (String)

  • (NilClass)

    引数で与えられたクッキーが定義されていない場合 nil



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/al_main.rb', line 199

def self.get_cookie( name )
  if ! @@cookies
    @@cookies = {}
    http_cookie = ENV['HTTP_COOKIE']
    return nil  if ! http_cookie

    cookies = http_cookie.split( ';' )
    cookies.each do |c|
      (k,v) = c.split( '=', 2 )
      next if ! v
      @@cookies[k.strip.to_sym] = decode_uri_component( v )
    end
  end
  
  return @@cookies[name.to_sym]
end

+ (Object) handle_error(ex)

エラーハンドラ



88
89
90
91
# File 'lib/al_main.rb', line 88

def self.handle_error( ex )
  __send__( AL_ERROR_HANDLER, ex )  if ex.class != SystemExit
  exit
end

+ (Object) handle_error_display(ex)

エラーハンドラ:エラー詳細表示



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/al_main.rb', line 127

def self.handle_error_display( ex )
  send_http_headers()

  puts AL_TEMPLATE_HEADER
  puts AL_TEMPLATE_BODY
  puts '<h1 class="al-error-display">Alone: Error detected.</h1>'
  puts "<h2 class=\"al-error-display\">#{ex.class} occurred.</h2>"
  puts '<pre class="al-error-display">'
  puts '    ' + escape_html( ex.message )
  puts '</pre>'

  puts '<h2 class="al-error-display">Backtrace</h2>'
  puts '<pre class="al-error-display">'
  ex.backtrace.each do |bt|
    puts '    ' + escape_html( bt )
  end
  puts '</pre>'

  puts '<h2 class="al-error-display">Environment</h2>'
  puts '<pre class="al-error-display">'
  `env`.split("\n").each do |e|
    puts '    ' + escape_html( e )
  end
  puts '</pre>'
  puts AL_TEMPLATE_FOOTER
end

+ (Object) handle_error_static_page(ex)

エラーハンドラ:静的ページを表示



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/al_main.rb', line 97

def self.handle_error_static_page( ex )
  status_code = nil
  status_message = nil

  # check status code in @@headers.
  @@headers.each do |h|
    if /^Status: (\d+)(.*)$/ =~ h
      status_code = $1
      status_message = $1 + $2
    end
  end
  if ! status_code
    status_code = "500"         # default 500 Internal Server Error
    status_message = "Internal Server Error"
    Alone::add_http_header( "Status: 500 Internal Server Error" )
  end

  # display error page.
  send_http_headers()
  begin
    print File.read( "#{AL_BASEDIR}/templates/#{status_code}.html" )
  rescue
    print status_message
  end
end

+ (Object) main

Note:

ユーザコードがブロックで渡されるので、それを実行する。 例外はすべてキャッチして、正当なhtmlで表示する。

メイン



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/al_main.rb', line 66

def self.main()
  #
  # リダイレクトするなら、ヘッダ出力のみで終了(htmlコンテンツは必要ない)
  #
  if @@flag_redirect
    send_http_headers()
    exit
  end

  begin
    yield()
    send_http_headers()

  rescue Exception => ex
    handle_error( ex )
  end
end

+ (String) make_uri(arg = {})

Note:

このメソッドは、escape_html()した値を返さない。 生成した値は、アトリビュート値にもテンプレートにも使われる。 少々危険な気もするが、エスケープはテンプレートエンジンの仕事にしなければ アプリケーションが破綻する。

リンク用のURIを生成する

Parameters:

  • (Hash) arg (defaults to: {})

    引数ハッシュ

Options Hash (arg):

  • (String) :ctrl N/A

    コントローラ名

  • (String) :action N/A

    アクション名

  • (String) :(oters) N/A

    その他のパラメータ

Returns:

  • (String)

    生成したURI



329
330
331
332
333
334
335
336
337
338
339
# File 'lib/al_main.rb', line 329

def self.make_uri( arg = {} )
  uri = "#{ENV['SCRIPT_NAME']}?ctrl=#{arg[:ctrl] || @@ctrl}"
  uri << "&action=#{arg[:action]}"  if arg[:action]

  arg.each do |k,v|
    next if k == :ctrl || k == :action
    uri << "&#{k}=#{v}"
  end

  return uri
end

+ (Object) redirect_to(uri)

リダイレクト設定

Parameters:

  • (String) uri

    リダイレクト先のURI



259
260
261
262
263
264
265
266
267
268
# File 'lib/al_main.rb', line 259

def self.redirect_to( uri )
  if @@flag_send_http_headers
    raise "HTTP header was already sent."
  end
  raise "Invalid URI"  if /[\r\n]/ =~ uri

  @@headers << "Location: #{uri}"
  @@headers << "Status: 302 Found"
  @@flag_redirect = true
end

+ (String) request_uri

リクエストされたURIを返す

Returns:

  • (String)

    リクエストされたURI



302
303
304
305
306
307
308
309
310
311
312
# File 'lib/al_main.rb', line 302

def self.request_uri()
  if ENV['REQUEST_URI']
    return ENV['REQUEST_URI']
  end

  if ENV['QUERY_STRING']
    return "#{ENV['SCRIPT_NAME']}?#{ENV['QUERY_STRING']}"
  end

  return ENV['SCRIPT_NAME']
end

+ (Object) send_http_headers

Note:

送信済みなら何もしないので、何度よんでも問題ない。

httpヘッダの送信



176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/al_main.rb', line 176

def self.send_http_headers()
  return  if @@flag_send_http_headers
  @@flag_send_http_headers = true

  flag_content_type = false
  @@headers.each do |h|
    puts h
    flag_content_type = true  if h.start_with?( "Content-Type:" )
  end
  if ! flag_content_type 
    print "Content-Type: text/html; charset=#{AL_CHARSET}\n"
  end
  print "\n"
end
Note:

httpヘッダに出力する関係上、ヘッダ出力前にコールする必要がある。

クッキーの設定

Parameters:

  • (String) name

    クッキー名

  • (String) value

  • (String) expire (defaults to: nil)

    有効期限

  • (String) path (defaults to: nil)

    パス



227
228
229
230
231
232
# File 'lib/al_main.rb', line 227

def self.set_cookie( name, value, expire = nil, path = nil )
  cookie = "Set-Cookie: #{name}=#{encode_uri_component( value )}"
  cookie << "; expires=#{expire.to_s}"  if expire
  cookie << "; path=#{path}"  if path
  @@headers << cookie
end