Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

RubyのコードとデータをDATAと__END__と混合する

Rubyが、スクリプトが独自のソースファイルをデータのソースとして使用する方法を提供していることをご存知ですか?これは、1回限りのスクリプトや概念実証を作成するときに時間を節約できる巧妙なトリックです。ぜひチェックしてみてください!

DATAおよびEND

以下の例では、__END__という面白いキーワードを使用しています。 。 __END__の下のすべて Rubyインタープリターによって無視されます。しかし、さらに興味深いことに、rubyはDATAと呼ばれるIOオブジェクトを提供します 、__END__の下のすべてを読むことができます 他のファイルから読み取ることができるのと同じように。

次の例では、各行を繰り返して印刷します。

DATA.each_line do |line|
  puts line
end

__END__
Doom
Quake
Diablo

この手法の私のお気に入りの実用的な例では、DATAを使用しています。 ERBテンプレートを含めるため。 YAML、CSVなどでも機能します。 M

require 'erb'

time = Time.now
renderer = ERB.new(DATA.read)
puts renderer.result()

__END__
The current time is <%= time %>.

実際にDATAを使用できます __END__より上のコンテンツを読む キーワード。これは、DATA 実際には、ソースファイル全体へのポインタであり、__END__に早送りされます キーワード。印刷する前にIOオブジェクトを巻き戻すと、これを確認できます。以下の例では、ソースファイル全体を印刷します。

DATA.rewind
puts DATA.read # prints the entire source file

__END__
meh

複数ファイルのデリマ

この手法の大きな欠点の1つは、スクリプトが単一のソースファイルに収まり、そのファイルを含めるのではなく直接実行している場合にのみ実際に機能することです。

以下の例では、2つのファイルがあり、それぞれに独自の__END__があります。 セクション。ただし、DATAは1つしか存在できません グローバル。したがって、__END__ 2番目のファイルのセクションにアクセスできません。

# first.rb
require "./second"

puts "First file\n----------------------"
puts DATA.read

print_second_data()

__END__
First end clause

# second.rb

def print_second_data
  puts "Second file\n----------------------"
  puts DATA.read # Won't output anything, since first.rb read the entire file
end

__END__

Second end clause

snhorne ~/tmp $ ruby first.rb
First file
----------------------
First end clause

Second file
----------------------
複数のファイルの回避策

Sinatraには、__END__の後に複数のインラインテンプレートを配置することで、アプリに複数のインラインテンプレートを追加できる非常に優れた機能があります。 声明。次のようになります:

# This code is from the Sinatra docs at https://www.sinatrarb.com/intro.html
require 'sinatra'

get '/' do
  haml :index
end

__END__

@@ layout
%html
  = yield

@@ index
%div.title Hello world.

しかし、sinatraはこれをどの程度正確に行うことができますか?結局のところ、アプリはおそらくラックによってロードされるでしょう。 ruby myapp.rbを実行するつもりはありません 生産中!彼らはDATAを使用する方法を考え出したに違いありません 複数のファイルを使用します。

ただし、シナトラの情報源を少し掘り下げると、それらが一種の不正行為であることがわかります。 DATAを使用していません まったく。代わりに、彼らは以下のコードのようなことをしています。

# I'm paraphrasing. See the original at https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1284
app, data = File.read(__FILE__).split(/^__END__$/, 2)

__FILE__を読みたくないので、実際にはもう少し複雑です。 。それはsinatra/base.rbファイルになります。代わりに、関数を呼び出したファイルのコンテンツを取得したいと考えています。発信者の結果を解析することでこれを取得します。

呼び出し元関数は、現在実行中の関数が呼び出された場所を通知します。簡単な例を次に示します。

def some_method
  puts caller
end

some_method # => caller.rb:5:in `<main>'

これで、ファイル名をそこから取り出して、そのファイルのDATAに相当するものを抽出するのは非常に簡単です。

def get_caller_data
  puts File.read(caller.first.split(":").first).split("__END__", 2).last
end

悪ではなく善のために使用する

うまくいけば、これらのようなトリックはあなたが毎日使いたいものではないことは明らかです。クリーンで保守可能な大規模なコードベースを正確に作成できるわけではありません。

ただし、1回限りのユーティリティスクリプトまたは概念実証のために、迅速で汚いものが必要になる場合があります。その場合、DATA および__END__ かなり便利です。


  1. Rubyでファイルを読み書きする方法(例付き)

    今日は、Rubyでファイルを読み書きして、コンテンツを抽出し、新しいファイルを作成し、必要な情報を見つける方法を学びます。 これから説明します : コンテンツ 1Rubyでファイルを読み取る方法 2Rubyでファイルに書き込む方法 3つのRubyファイルメソッド 4つのディレクトリ操作 5FileUtilsモジュールの使用方法 6まとめ 6.1関連 やってみましょう! Rubyでファイルを読み取る方法 次のようにRubyでファイルを読み取ることができます: ファイルを開く 、open メソッド。 ファイルを読む 、ファイル全体、行ごと、または特定のバイト数。 ファイルを

  2. Windows 10 でファイル履歴を使用してデータを保存および復元する方法

    ハードドライブの故障、停電、その他の問題などの予期しない状況から重要なファイルやドキュメントを保存することがいかに重要であるかを理解しています.できれば、データを定期的にバックアップする必要があります。ただし、Windows OS について言えば、すべての重要なファイルを USB ドライブ (少量のデータの場合) やハード ドライブ (大量のデータの場合) などの外部ストレージ デバイスに定期的にコピーできます。気楽な人は、毎日 (または好みに応じて) クラウド ストレージにデータを自動的にバックアップできるソフトウェアを購入できます。一方、「ファイル履歴」と呼ばれる Windows 10 の