C#でメディアファイルをウインドウにドロップしたらそのメディアファイルの情報を表示する

このアプリを実行するとウインドウが表示されるので
そこにファイラーなどからメディアファイルをドロップしてください
そうすると、FFmpegのffprobe.exeを利用してその情報をウインドウに表示します

https://www.ffmpeg.org からffmpeg-xxxxxxxx-xxxxxxx-win64-static.zip をダウンロードして
その中にある ffprobe.exe をこのアプリと同じディレクトリに入れておいてください
(64bit版の場合、このアプリを管理者権限で実行してしまうと、管理者権限で実行中の物からしかドロップできませんので注意)


csc.exe -target:winexe mediafile_probe.cs

みたいな感じでコンパイルすればコマンドプロンプトは開きません

あと、フォントに「Yu Gothic UI」を指定してるので無い環境の場合は違うフォントを指定してください

using A_Console          = System.Console;
using A_Forms            = System.Windows.Forms;
using A_Application      = System.Windows.Forms.Application;
using A_DataFormats      = System.Windows.Forms.DataFormats;
using A_DragDropEffects  = System.Windows.Forms.DragDropEffects;
using A_DragEventArgs    = System.Windows.Forms.DragEventArgs;
using A_DragEventHandler = System.Windows.Forms.DragEventHandler;
using A_FormBorderStyle  = System.Windows.Forms.FormBorderStyle;
using A_MessageBox       = System.Windows.Forms.MessageBox;
using A_ScrollBars       = System.Windows.Forms.ScrollBars;
using A_TextBox          = System.Windows.Forms.TextBox;
using A_Process          = System.Diagnostics.Process;
using A_ProcessStartInfo = System.Diagnostics.ProcessStartInfo;
using A_Encoding         = System.Text.Encoding;
using A_Font             = System.Drawing.Font;
using A_FontStyle        = System.Drawing.FontStyle;
using A_GraphicsUnit     = System.Drawing.GraphicsUnit;
using A_Point            = System.Drawing.Point;
using A_Size             = System.Drawing.Size;

namespace AppMediaFileProbe
{
	public class Form1 : A_Forms.Form
	{
		private A_TextBox txt1;
		public Form1()
		{
			//Form1
			this.Name = "Form1";
			this.Text = "メディア情報解析 by ffprobe";
			this.ClientSize = new A_Size(1600, 800);
			this.FormBorderStyle = A_FormBorderStyle.FixedSingle;
			this.AllowDrop = true;
			this.DragDrop += new A_DragEventHandler(this.Form1_DragDrop);
			this.DragEnter += new A_DragEventHandler(this.Form1_DragEnter);
			//txt1
			this.txt1 = new A_TextBox();
			this.txt1.Name = "txt1";
			this.txt1.Font = new A_Font("Yu Gothic UI", 12F, A_FontStyle.Bold, A_GraphicsUnit.Point, ((byte)(128)));
			this.txt1.Location = new A_Point(5, 5);
			this.txt1.Multiline = true;
			this.txt1.ReadOnly = true;
			this.txt1.ScrollBars = A_ScrollBars.Both;
			this.txt1.Size = new A_Size(1590, 790);
			this.txt1.TabIndex = 1;
			this.Controls.Add(txt1);
		}
		private void Form1_DragDrop(object sender, A_DragEventArgs e)
		{
			string[] files = (string[])e.Data.GetData(A_DataFormats.FileDrop, false);
			txt1.Text = Call_ffprobe(files[0]);
		}
		private void Form1_DragEnter(object sender, A_DragEventArgs e)
		{
			if (e.Data.GetDataPresent(A_DataFormats.FileDrop))
			{
				e.Effect = A_DragDropEffects.Copy;
			}
		}
		private string Call_ffprobe(string file_name)
		{
			A_ProcessStartInfo psi = new A_ProcessStartInfo();
			psi.FileName = @".\ffprobe.exe";
			psi.Arguments = "\"" + file_name + "\"";
			psi.CreateNoWindow = true;
			psi.UseShellExecute = false;
			psi.RedirectStandardError = true;
			psi.StandardErrorEncoding = A_Encoding.UTF8;
			A_Process p = A_Process.Start(psi);
			return p.StandardError.ReadToEnd();
		}
		[System.STAThread]
		static void Main()
		{
			A_Application.EnableVisualStyles();
			A_Application.Run(new Form1());
		}
	}
}

C#でファイルのドラッグ&ドロップを受け付け出来るようにする

C#でFormを表示して ファイルのドロップを受け付けて
投げ込まれたもの(複数個なら最初の)が何だったのかをMessageBoxで表示します
以下のソースをcsc.exeに通すだけで出来ます(VisualStudioの環境は必須ではありません)

using A_Forms            = System.Windows.Forms;
using A_Application      = System.Windows.Forms.Application;
using A_DataFormats      = System.Windows.Forms.DataFormats;
using A_DragDropEffects  = System.Windows.Forms.DragDropEffects;
using A_DragEventArgs    = System.Windows.Forms.DragEventArgs;
using A_DragEventHandler = System.Windows.Forms.DragEventHandler;
using A_FormBorderStyle  = System.Windows.Forms.FormBorderStyle;
using A_MessageBox       = System.Windows.Forms.MessageBox;
using A_Size             = System.Drawing.Size;
using A_EventArgs        = System.EventArgs;
using A_EventHandler     = System.EventHandler;

namespace AppFileDrop
{
	public class Form1 : A_Forms.Form
	{
		public Form1()
		{
			this.Name = "Form1";
			this.ClientSize = new A_Size(800, 600);
			this.FormBorderStyle = A_FormBorderStyle.FixedSingle;
			this.Load += new A_EventHandler(this.Form1_Load);
			this.AllowDrop = true;
			this.DragDrop += new A_DragEventHandler(this.Form1_DragDrop);
			this.DragEnter += new A_DragEventHandler(this.Form1_DragEnter);
		}
		private void Form1_Load(object sender, A_EventArgs e)
		{
			// Form1.Load event
		}
		private void Form1_DragDrop(object sender, A_DragEventArgs e)
		{
			string[] files = (string[])e.Data.GetData(A_DataFormats.FileDrop, false);
			A_MessageBox.Show(files[0]);
		}
		private void Form1_DragEnter(object sender, A_DragEventArgs e)
		{
			if (e.Data.GetDataPresent(A_DataFormats.FileDrop))
			{
				e.Effect = A_DragDropEffects.Copy;
			}
		}
		[System.STAThread]
		static void Main()
		{
			A_Application.EnableVisualStyles();
			A_Application.Run(new Form1());
		}
	}
}

C#でフォント選択ダイアログを表示させる

細かなことは省いてただ単純に フォントを選択させてそれが何だったのかを表示させるだけです
VisualStudioを使う事も無く、単にcsc.exeにぶち込めばexeファイルが生成されます

using A_Console = System.Console;
using A_FontDialog = System.Windows.Forms.FontDialog;
namespace AppFontSelect
{
	class FontSelect
	{
		static void Main()
		{
			A_FontDialog fd = new A_FontDialog();
			fd.ShowDialog();
			A_Console.WriteLine(fd.Font.Name);
			A_Console.WriteLine(fd.Font.Size);
			A_Console.WriteLine(fd.Font.Style);
		}
	}
}

(node.js)(javascript)(promise) thenからthenへ値を渡せるようになろう

node.jsに関する記事一覧→ http://morakana.hatenablog.jp/entry/2018/03/09/174557




前回の内容のおさらいです、

「new Promise()」で作った Promiseのインスタンスの内部の結果を受けるのは「then」で
それを受けた thenが返すのも Promiseのインスタンスでした
ならば、 thenが返したPromiseのインスタンスも 同じくthenで繋いでいける

ということでしたね


では thenからthen へ繋ぐ場合を具体的にどう書くのかを見ていきます


new Promise()」 で Promiseのインスタンスを作る時には

prms1 = new Promise( (resolve, reject)=>{ resolve('hello'); } );

こんな感じでしたね(簡素化のために成功時の処理しか書いていません)

そして、 Promsieのインスタンスに .thenとして繋ぐことで
Promise内の処理が 成功した時と失敗した時の2ルートで結果を取得することになります

prms2 = prms1.then( (val)=>{ return(Promise.resolve(val + ' world')); } );

ここも簡素化のために成功時のみを書いています

さて、ここでちょっと見慣れない「return Promise.resolve()」というものが出てきました
大方の察しは付くと思いますが
これが「次のthenへ成功時の結果を渡すもの」ということになります
同様に『失敗時だったら「return Promise.reject()」だろうな』と想像できますね

では、ここまでの内容を纏めて、一つ目のthenが渡してきた値を、二つ目のthenで受けて表示させてみます

prms1 = new Promise( (resolve, reject)=>{ resolve('hello'); } );
prms2 = prms1.then( (val)=>{ return(Promise.resolve(val + ' world')); } );
prms2.then( (val)=>{ console.log(val); } );

「hello world」という表示になったと思います

今回はほぼ即時に実行終了するので実感が無いと思いますが

「hello」という結果が3秒後に出た場合でも
それまでは val + ' world'という処理は行われませんし
 val + ' world' という処理に5秒かかったとしても
その結果が出るまでは 「hello world」とは表示されない

ということです


ちなみに・・・・
thenの戻り値が Promiseのインスタンスということは
「Promise.resolve()」の戻り値が Promiseのインスタンスということになるだろうし
「return Promise.resolve()」の所は 「return new Promise()」でも書けるはずですよね?
つまり

prms1 = new Promise( (resolve, reject)=>{ resolve('hello'); } );
prms2 = prms1.then((val)=>{
	return(new Promise( (resolve, reject)=>{ resolve(val + ' world');}));
});
prms2.then( (val)=>{ console.log(val); } );

とも書けるわけです、というか同じ意味になります
「Promise.resolve()」 は 「『new Promise()』の成功時(resolve)の部分」に相当するわけです
同じく失敗時なら 「Promise.reject()」 は 「『new Promise』の失敗時の部分」ということですね
相当するとはいえ「new Promise()」で書こうとすると構造的にもかなり煩雑な形になってしまうので
「Promise.resolve()」「Promise.reject()」の方を使った方がいいかと思います。

(node.js)(javascript)(promise) Promiseのインスタンスはチェイン出来る

node.jsに関する記事一覧→ http://morakana.hatenablog.jp/entry/2018/03/09/174557



前回までは new Promise したものを 変数に代入して
その変数に .then と続けることで
Promise内の処理が 成功 又は 失敗 した時のデータを受けていました

prms = new Promise(()=>{});
prms.then();



ただこれは、変数に代入せずに、直接 .thenと続けても機能します

new Promise(()=>{}).then();

まぁ、ここまでは、単に式の書き方の違いなので分かると思います


では、thenの戻り値はというと・・・ なんと Promiseなのです
実際に

const puts = console.log;
puts(
	new Promise(()=>{}).then()
);

みたいにして確認してみると

Promise { <pending> }

との結果が得られます、つまりPromiseが返ってきているのです


という事は then に .then と続けてもPromiseが返り続けるということになるのです
実際に

const puts = console.log;
puts(
	new Promise(()=>{})
	.then().then().then().then()
);

こんな感じにしても得られる結果はさっきと同じ

Promise { <pending> }

となります


じゃあこの事に何のメリットがあるのか?というと
thenの内容 は Promiseの成功か失敗かが確定しないと実行されません
つまり
前のthenが返した Promiseの中身の処理が 成功したか失敗したかが確定するまでは
次のthenの内容は 実行されない

ということなのです
これをうまく利用すれば 非同期処理を同期させて実行することも可能になるわけです

(node.js)(javascript)(promise) 成功時と失敗時の処理を両方書けるようになろう

node.jsに関する記事一覧→ http://morakana.hatenablog.jp/entry/2018/03/09/174557



まずは、前回の基本的なPromise使い方のおさらいです

#!/usr/local/bin/node

const puts = console.log;
const print = (str)=>{process.stdout.write(str)};

const prms = new Promise((resolve, reject)=>{
	resolve('hello world!');
});

prms.then(
	(val)=>{
		print('on_resolve: ');
		puts(val);
	}
);

これではまだPromise内の処理が成功することしか想定してない状態ですね


では今度は 成功した場合 と 失敗した場合 があるケースについて書いてみます
いろいろと難しい処理を書くと分かりづらくなるので
1/2の確率で成功する場合と失敗する場合で書いてみます

#!/usr/local/bin/node

const puts = console.log;
const print = (str)=>{process.stdout.write(str)};

// 0 ~ 999 の乱数を発生させる関数を定義
const rnd = ()=>{return Math.floor(Math.random()*1000)};

// rndで乱数を発生させて
// 0 ~ 499 なら成功扱い
// 500 ~ 999 なら失敗扱いします
const prms = new Promise((resolve, reject)=>{
	if (rnd() <= 499){
		resolve('処理成功');
	}else{
		reject('処理失敗');
	}
});

prms.then(
	(val)=>{
		print('on_resolve: ');
		puts(val);
	},
	(val)=>{
		print('on_reject: ');
		puts(val);
	}
);

前回と比べると本当にちょっと追加しただけですが
thenに対して 成功したと伝えるには resolve を、 失敗したと伝えるには reject を実行し
then側は、第一引数で成功時第二引数で失敗時 を受ける
ということを覚えておきましょう

(ruby) コピペで使えるライブラリ集

■ (ruby)(コピペで使えるライブラリ集) パターンにマッチングしたファイルの一覧を配列で返すメソッド

パターンでファイルを検索してマッチしたものを配列で取得するものです、戻り値をある程度カスタマイズできます
■ (ruby)(コピペで使えるライブラリ集) カレントディレクトリにテンポラリディレクトリを作るメソッド
カレントディレクトリを汚したくない時にちょっとしたテンポラリディレクトリを作れます

(ruby)(コピペで使えるライブラリ集) カレントディレクトリにテンポラリディレクトリを作るメソッド

ruby コピペライブラリ一覧→ http://morakana.hatenablog.jp/entry/2018/03/13/100032



この create_temp_path メソッドは、カレントディレクトリにテンポラリディレクトリを作り、
作成に成功したらその絶対パス名を返します

何らかの問題で テンポラリディレクトリの作成に失敗したら nil が返ってきます
あくまでカレントディレクトリに作成される仕様ですので、カレントディレクトリ以外の場所は指定できません


テンポラリディレクトリはデフォルトの状態だと作った時の時間で生成されます
フォーマットは 年-月-日_時_分_秒_1秒未満5桁(%Y-%m-%d_%H-%M-%S-%5N)になります

2018-03-13_08-08-49-47544

複数個作っても出来た時間でソートできるメリットがあります


引き数に strftimeのフォーマット文字列を指定することでカスタマイズすることも可能です
単純に tempだけでいいなら

create_temp_path('temp')

みたいにも書けます
フォーマット文字列に関して詳しくはこちら https://docs.ruby-lang.org/ja/latest/method/Time/i/strftime.html を参照してくださぃ


create_temp_pathメソッド定義

def create_temp_path(format = '%Y-%m-%d_%H-%M-%S-%5N')
	path_name = Time.now.strftime(format)
	begin
		Dir.mkdir(path_name)
	rescue
		return nil
	end
	return(File.expand_path(path_name))
end

(ruby)(コピペで使えるライブラリ集) パターンにマッチングしたファイルの一覧を配列で返すメソッド

ruby コピペライブラリ一覧→ http://morakana.hatenablog.jp/entry/2018/03/13/100032



この enum_files メソッドは、パターンにマッチングしたファイル名一覧を取得します


enum_files(['./*'])

で、マッチングしたファイルのファイル名が絶対パスの配列で返ってきます


パターンを複数個指定したい場合は、パターンを配列で指定します

enum_files(['./*.rb', './*.txt']) 



絶対パス以外の形式でファイル名を取得したい場合
第二引数にフォーマット文字列を指定することで戻り値をカスタマイズ出来ます
フォーマット文字は

a 絶対パス名
d ディレクトリ(絶対パス)まで
f ファイル名(拡張子を含む)
F ファイル名(拡張子を含まない)
e 拡張子のみ

の組み合わせで指定します
たとえば

enum_files(['./*.rb', './*.txt'], 'aFfe')

のようにすると、対応した各ファイルに対して
[<絶対パス名>, <ファイル名(拡張子を含まない)>, <ファイル名(拡張子を含む)>, <拡張子のみ>]
がセットされた配列の配列で返します
無効なフォーマット文字を入れた場合は nil が入ります


enum_filesメソッド定義

def enum_files(ptn, format = 'a')
	files = []
	Dir.glob(ptn, File::FNM_CASEFOLD).each{|i1|
		fullpath_name = File.expand_path(i1)
		file = []
		format.split('').each{|i2|
			file << (
				case i2
				when 'a'
					fullpath_name
				when 'd'
					File.dirname(fullpath_name)
				when 'f'
					File.basename(fullpath_name)
				when 'F'
					File.basename(fullpath_name, '.*')
				when 'e'
					File.extname(fullpath_name)
				else
					nil
				end
			)
		}
		files << file
	}
	return(files)
end



同等の機能で配列クラスを拡張するバージョンはこちら

class Array
	def enum_files(format = 'a')
		files = []
		Dir.glob(self, File::FNM_CASEFOLD).each{|i1|
			fullpath_name = File.expand_path(i1)
			file = []
			format.split('').each{|i2|
				file << (
					case i2
					when 'a'
						fullpath_name
					when 'd'
						File.dirname(fullpath_name)
					when 'f'
						File.basename(fullpath_name)
					when 'F'
						File.basename(fullpath_name, '.*')
					when 'e'
						File.extname(fullpath_name)
					else
						nil
					end
				)
			}
			files << file
		}
		return(files)
	end
end

配列にファイル検索パターンをセットしてから
配列のenum_filesインスタンスメソッドを実行します
引数はフォーマット文字列を指定します(省略可)

['./*.rb', './*.txt'].enum_files('aFfe')

で、上の例と同等の機能になります

node.jsのまとめ

■ (node.js)(javascript) 外部プログラムを呼び出して、それに標準入力をして、それの標準出力を取得する

node.jsから呼び出した外部プログラムに標準入力を与えたり外部プログラムからの標準出力を受け取る方法

■ (node.js)(javascript) インスタンスのクラス名を調べたい

typeofでは調べきれないインスタンスのクラスを調べる方法

■ (ruby)(python3)(node.js)(c++)(java) いろんな言語の超基本的なクラス定義を書き並べてみる

基本的なクラスの定義の仕方をいろんな言語で書いてみた


■ (node.js)(javascript)(promise) まずはPromiseを使う時の超基本
(シリーズ:Promiseの使い方講座) Promiseが機能する最小限の構成を説明しています

■ (node.js)(javascript)(promise) 成功時と失敗時の処理を両方書けるようになろう

(シリーズ:Promiseの使い方講座) 前回は成功しか想定してなかったのですが、今回は失敗時の処理もサポートさせます

■ (node.js)(javascript)(promise) Promiseのインスタンスはチェイン出来る

(シリーズ:Promiseの使い方講座) thenをチェインするメリットとは?というお話

■ (node.js)(javascript)(promise) thenからthenへ値を渡せるようになろう

(シリーズ:Promiseの使い方講座) 具体的にthenをチェインさせてみます



■ node.jsのPromiseはどう書いたら同期的に処理したいところを分かりやすくできるか考察中
番外編です、Promiseの使い方を考察中に書いたもの

rubyのまとめ

■ (ruby)(rbenv) rbenvでrubyをインストール

rbenvを使ってrubyをインストールする方法
■ (WSL)(ruby) WSLの環境でpryを使うと最初にパーミッションの警告が出て五月蠅い場合
Windows Subsystem for Linux環境下で pryを使うと 最初のコマンドの実行時にパーミッション関係の警告が出る場合の対処法
■ (ruby)(python3)(node.js)(c++)(c#)(java) いろんな言語の超基本的なクラス定義を書き並べてみる
基本的なクラスの定義の仕方をいろんな言語で書いてみた
■ (ruby) 後置if式で実行内容を複数個書きたい場合
後置ifに複数個の処理を掛けたい場合のやり方
■ (ruby) rubyでは ifやcaseは if文 case文 ではなく if式 case式 である
rubyでは ifやcase等にも戻り値があり、式の中に組み込めるというお話

(node.js)(javascript)(promise) まずはPromiseを使う時の超基本

node.jsに関する記事一覧→ node.jsのまとめ



関数の中に関数を書くパターンが続くのでそれに慣れていないと混乱してしまいがちです
まずは Promiseを使う時の超基本的な流れからです

Promiseのインスタンスを生成して
その中で非同期処理を行い
その結果をresolveで受け側の処理に渡し
先程生成したPromiseのインスタンスのthen関数が受け側になり
thenの中で後処理を行います

ハハッ!!、なんのこっちゃ~


実際に見てみた方が分かりやすいと思います

#!/usr/local/bin/node

// コンソール出力を簡潔に実行できるように
const puts = console.log;
const print = (str)=>{process.stdout.write(str)};

// Promiseのインスタンスを作成します
// Promiseのコンストラクタに渡す引数は
// 第一引数に成功時に呼び出す関数を受ける変数名
// 第二引数に失敗時に呼び出す関数を受ける変数名
// 一般的には resolve と reject という名前を使います
const prms = new Promise((resolve, reject)=>{
	// 今回は例を簡単にするため成功時のみを想定し
	// resolveの引数に値を決め打ちしてますが
	// 実際はここに非同期処理を書いて
	// その結果をresolveの引数に渡します
	// この値が受け側の処理に渡されることになります
	// 例えば、Promise形式ではない非同期処理をここに書くことによって
	// Promise形式として取り扱えるようになります
	resolve('hello world!');
});

// prms には Promiseのインスタンスがセットされています
// このインスタンスに .then と続けると
// 渡されてきた値を受け取ることが出来ます
// Promiseの中身の処理が非同期処理であっても
// resolve か reject が実行された後にthenの中身が実行されます
// thenの仕様は
// then(<成功時に実行される関数>, <失敗時に実行される関数>);
// となっています
// 第一引数の方の関数の引数には resolveで引き渡されてきた値が入っています
// 第二引数の方の関数の引数には rejectで引き渡されてきた値が入っています(省略可能)
prms.then(
	(val)=>{
		puts('on_resolve');
		puts(val);
	}
);

node.jsのPromiseはどう書いたら同期的に処理したいところを分かりやすくできるか考察中

node.jsに関する記事一覧→ node.jsのまとめ



他の手段があるのも薄々知ってはいるんですが
今回は、あくまでもPromiseで書いたらどうなのかを考えている最中の、(仮)的な記事です


非同期的に実行しても問題なく
それらが全部終わったら○○しろという場面なら
Promise.all(<Promiseの配列>)等でやれば楽ちんですが
非同期処理が主体の仕様だと、いざ同期させたい時がかなり厄介ですよね


たとえばhttpでGETするという比較的時間の掛かる遅い処理の後に
ファイルを読み込みたい場合に、それらを単に並行で書いてしまうと
確実にファイル読み込みの方が先に発動して不具合が出るのは目に見えていますね
そんな時にどう書けば「思ったように実行順序を制御」した上で「可読性を確保できるか」を
考えている最中の記事になります


読み込むファイルはとりあえずutf-8で掛かれた、こんな感じのダミーデータです
ファイル名は './utf8_1.txt' としてます


utf-8
サンプルテキスト1


とりあえず意図した順番で実行の制御が出来ているのは、こんな感じ
同期的にやるんなら .thenでチェインしまくればいいというのはわかってはいるんですが
後から見た時になんかぱっと見ではわかりにくくなるような気がして
なんかメリハリみたいなのを付けれないかなぁと思ってるところです

#!/usr/local/bin/node

const puts = console.log;

// XMLHttpRequestのGETをPromise化
const get_html_pro = (url)=>{
	return(new Promise((resolve, reject)=>{
		puts('>>>> ' + url + ' のサイズを計測開始');
		const xhr = new (require("xmlhttprequest").XMLHttpRequest);
		xhr.open('GET', url, true);
		xhr.onload = ()=>{
			puts('>>>> ' + url + ' のサイズ計測完了')
			resolve(Buffer.byteLength(xhr.responseText));
		};
		xhr.send();
	}));
};

// fsのreadFileをPromise化
const readFile_pro = (filename, charset = 'utf-8')=>{
	return(new Promise((resolve, reject)=>{
		puts('>>>> ファイル読み込み開始');
		require('fs').readFile(
			filename, charset,
			(err, txt)=>{
				resolve(txt);
			}
		);
	}));
};

const url = 'https://www.youtube.com';
const html_pro = get_html_pro(url);

const phase1 = html_pro.then((val)=>{
	puts('>>>> ページサイズ: ' + val);
});

const phase2 = phase1.then(()=>{
	puts('>>>> ファイル読み込みフェイズ開始');
	return(
		readFile_pro('./utf8_1.txt')
		.then((val)=>{
			puts('------------------------------------');
			puts(val)
			puts('------------------------------------');
			puts('>>>> ファイル読み込みフェイズ完了');
		})
	);
});

phase2.then(()=>{
	puts('>>>> 全行程終了');
});


結果としてはこんな感じの表示になります

>>>> https://www.youtube.com のサイズを計測開始
>>>> https://www.youtube.com のサイズ計測完了
>>>> ページサイズ: 490724
>>>> ファイル読み込みフェイズ開始
>>>> ファイル読み込み開始
------------------------------------

utf-8
サンプルテキスト1


------------------------------------
>>>> ファイル読み込みフェイズ完了
>>>> 全行程終了

ページサイズは実行するたびに変わる場合があります


まぁ、まだいろいろと試行錯誤中なのでまた考えがまとまったら正式な記事にするかも

(ruby) rubyでは ifやcaseは if文 case文 ではなく if式 case式 である

rubyに関する記事一覧→ rubyのまとめ



だいたいの言語って ifって文ですよね?、でもrubyでは ifも式なんです、caseも式なんです


if式ってなんやねん!?
って感じですが、まぁ論より証拠

puts(
	if true then
		100
	end
)

を実行すると 100 と表示されます
つまり trueだった場合その中の処理が実行され
一番最後の処理の戻り値が if式の結果 として返ってくるのです


もちろん、else や elsif が加わった場合も同じです

puts(
	if false then
		100
	else
		200
	end
)

これなら 200になります


caseも同じく

val = 2
puts(
	case val
	when 1
		'a'
	when 2
		'b'
	when 3
		'c'
	else
		'z'
	end
)

val に 2 がセットされているので表示されるのは b になります


今回、if式とcase式を紹介しましたが、実は他にもrubyの制御構造は戻り値を持つものが多いのです

puts(
	(100 if true)
)

100 が表示される

puts(
	(false ? 100 : 200)
)

200 が表示される


puts(
        unless false
                100
        end
)

100 が表示される

c = 0
puts(
	while
		c += 1
		break(c) if (c > 10)
	end
)

11 が表示される



など、他にもまだまだ有ります、もし興味を持ったのなら
もっと詳しい内容 Rubyリファレンスマニュアル → 制御構造 を参照してください

(ruby) 後置if式で実行内容を複数個書きたい場合

rubyに関する記事一覧→ rubyのまとめ



rubyには 先に実行内容を書いて、その後に if を挟んで 条件式を書く書き方があります
if修飾子 とか 後置if って言われているやつですね

puts('hello') if true

便宜上 trueと書いてますが、この部分に条件式を書くわけですね
この例では条件式は true なので puts('hello')が実行されます


ただし実行されるのは ifの左隣の一つだけです
複数個の処理を対象としようとして

puts('hello'); puts('world') if false

と書き 条件式がfalseの場合なら「hello」も「world」も表示されない のを期待しても
思ったような動作はせず
「hello」は true false に関わらず表示されてしまいます。
つまり ;を使ってワンライナーで書いたとしても
puts('hello') の方は 後置ifには掛かっていないという事ですね


こういった場合には この二つの処理を () で括って纏めてしまえば
二つとも 後置if に掛ける事が出来ます

(puts('hello'); puts('world')) if false


複数行に渡って処理を書く必要がある時は 普通のif式を使った方が良いとは思いますが
後置if でも複数行に渡る処理を書く事は不可能ではありません

(
	puts('hello')
	puts('world')
	exit()
) if true
sleep(100)

この例では3行とも実行されますので sleep以前に exitで実行が終了されます


少し実用的な書き方をすると

(puts('コマンドラインオプションで入力ファイル名を指定してください'); exit(0)) if (ARGV[0] == nil)

こういう感じになりますかね