Ruby公式サイトの他言語とRubyの違いを眺めてみて

Ruby公式サイトの他の言語とRubyの違いを眺めてみて

www.ruby-lang.orgの多言語からのRuby入門が面白かった。
他の言語と同じところ、違うところがまとめられている。
個人的にPythonとJavaが得意で、そこを眺めてみたが、こういう風にまとめられていると導入しやすいと思う。
気になったところを書き出してみる。

irbと言われる対話型の実行環境がある

この環境はとても便利。使ったことのないクラスを使う必要がある場合や、普段から使っているけどなかなか覚えられないsubstringの区切り位置を確認するときに重宝する。
文字列の2バイト目から5バイト欲しいときはどう指定するのか。対話画面があるとすぐに試せる。

今でこそ、Javaにもjshellができたが、それまでは小さなプログラムを作って、コンパイルして実行する必要があった。Eclipse 2の頃はスクラッチパットがあったが、今はどうなのだろう。
irbでいろいろ試しながら、スクリプトを作ることにしよう。

三重引用符で複数行リテラル

これは、Pythonでも好きなところ。Rubyでも使えるのは良いことだ。
Javaだったら、StringBuilder使うのも面倒なので、Propertiesにでも書き出しておくだろうか。

リストは[]、辞書は{}

PythonのTupleは無いようだ。あまり使わないから、どっちらでもよいが。

メソッド呼び出しの括弧はオプション

さすがPerlの次の言語だ。メソッドの呼び出しに括弧がいらない。Perlもそうであった。
昔のVBの様に戻り値の無いときの利用なら許容範囲かと思う。

True、Falseはtrueとfalse。Noneの変わりはnil。

PythonもTrue、Falseはtrueとfalseになってくれれば良いのに。
Noneとnilはnullになってしまえば良いのに。

importの代わりにrequireを使う

JRubyから始めたので、requireとimportの違いがいまだによくわからない。

MyClass.new()

インスタンスの作成が独特。new()もメソッドの扱いなのだろうか。
PythonならMyClass()。Javaならnew MyClass()。知ってしまえば、どれでも大した差はないか。

==とequals()

Rubyで文字列の比較は==。Javaならequals。
Rubyにはequalsは無く、equal?がある。しかしRubyのequal?はオブジェクトの比較用。Javaとは逆の動きだ。

まとめ

RubyもPythonもJavaも違いがあって面白い。
本当は何か1つの言語を極めるべきなのかもしれないけど、同じ言語ばかりだと飽きてしまうので、あれもこれも使っていきたいと思っている。

同じタグの記事
同じカテゴリの記事

JRubyを久しぶりに

JRubyを久しぶりに

ツールを作る。いつもの通りJythonを使おうと思ったが、時間もあるのでJRubyにした。
以前は、JavaのAPIを繰り返し呼び出すだけの簡単なプログラムだったが、今回は少しだけJRubyでロジックも書いてみた。穴にはまった。

定数クラスから定数を取得するときは::を使う

java.awt.Colorから色を取得しようと思った。

1
2
3
4
5
6
7
8
9
10
11
import java.awt.Color
import java.awt.image.BufferedImage

bi = BufferedImage.new(100, 100, BufferedImage::TYPE_INT_RGB)
g = bi.createGraphics()

g.color = Color.BLUE
# → エラー

g.color = Color::BLUE
# → OK

Rubyでは、メソッドの呼び出しのみを.(ピリオド)で行い、その他の呼び出しは::(コロン2つ)を利用するようだ。
メソッドの呼び出しは.でも::でもどちらでも良いらしい。
java.awt.Colorの.はピリオドでも良いようだ。しかし、java.awt.Color::BLUEは::だ。なんだこれ。

Javaクラスのimportはimport

Rubyの外部ファイル読み込みはrequire。
だからといって、Javaのクラスがすべて外部ファイルで定義されているわけではないので、requireではいけない。javaと同じようにimportを利用する。

1
2
3
4
5
6
7
8
require "java"
# → これはJRubyを組むときは読んでおいた方が良いらしい。

require "java.awt.Color"
# → エラー

import "java.awt.Color"
# → OK

単純なセッター、ゲッターはプロパティの様に呼び出しても良い

これは、なかなか面白い。
また、キャメルケースなメソッドをスネークケースに変換しても呼び出せる。
メソッドの括弧も省略できる。

1
2
3
4
5
6
7
8
9
10
11
g.setColor(Color::RED)
# → Java的。しかしエラーではない。

g.set_color(Color::GREEN)
# → まだJava的。しかしエラーではない。

g.set_color Color::BLUE
# → もう少し。しかしエラーではない。

g.color = Color::YELLOW
# → OK

ゲッター、セッターをプロパティとして扱えるのはKotlinっぽい。

ブロックコメント

ブロックコメントは

1
=begin

から

1
=end

に適用される。
よく、ソースの先頭に覚書を残すので、ブロックコメントの使い方は覚えておかなくては。
しかし、ネットをみると、ブロックコメントはあまり使わないらしい。
行コメントの#を使うようだ。今はIDEが良くできているので、各行に#を補ってくれるのだろう。
また、Javaでも言われているが、ブロックコメントの中にブロックコメントは書けないので、そういう時のためにブロックコメントは残しておくのだろうか。

しかし、Pythonと同様に複数行コメントに三重引用符が使える。
これでコメントを残しても良いのかな?

スクリプト引数

ARGVに引数が入っている。ARGVは配列。sizeやlengthで引数の数を確認できる。

1
2
3
4
5
puts ARGV.size
puts ARGV.length
if ARGV.size > 0
    puts ARGV[0]
end

また、$0にスクリプト(コマンド)そのものが入っている。

1
2
puts $0
# → JRubyのirbで実行したらjirbが返ってきた。

まとめ

JRubyも良い言語だ。簡便に書けるし、実行速度も不足ない。
JythonとJRuby、どちらを選ぶかはなかなか悩む。

同じタグの記事
同じカテゴリの記事

Pythonでデータクラス。その後。

Pythonでデータクラス。その後。

Python3.6でデータクラスの使用方法を知ってから、typing.NamedTupleを使ってPythonツールを作ってきた。しかし、今更ながらPython2.7(Jython)のツールを作る必要がでてきた。データクラスが使えない。
と思って、ドキュメントを見ていたら、collections.namedtupleはPython2.6から使えた。じゃあ、これを使えばいいか。

collections.namedtuple

1
2
3
4
5
from collections import namedtuple

Point = namedtuple('Point', 'x,y')
pos = Point(10, 20)
print(pos)

便利だ。__init__や__str__、__repr__まで実装されている。
それにVisual Studio Codeがプロパティを認識してくれている。

しかしtupleなので、プロパティの変更ができない。

1
2
3
4
>>> pos.x = 15
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

けど方法がないわけではない。

_replace

1
2
pos = pos._replace(x=15)
print(pos)

tupleなので変更はできない。しかし、プロパティを変更した新しいtupleを返してくれる。
これで、プロパティの変更のようなことができた。

namedtupleはクラスだ。したがって継承できる。
初期値として渡すような項目はnamedtupleとして定義し、変更する必要があったり、後から設定するようなプロパティは、そのnamedtupleを継承したクラスの方で定義してもよい。

namedtupleの継承(拡張)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from collections import namedtuple

Point = namedtuple('Point', 'x,y')
class MyPoint(Point):
    z = 0

    def move_z(self):
        self.z += 1

    def __str__(self):
        return 'X:{} Y:{} Z:{}'.format(
            self.x, self.y, self.z)

pos = MyPoint(10, 20)
pos.z = 30
pos.move_z()
print(pos)

これで不足ないデータクラスが作成できた。
この例では__str__を書き換えているが、本当は__repr__も書き換えておかないといけない。
__repr__を書き換えるなら、__init__も書き換える必要があるが・・・

まとめ

Python2.7でも、ここまでできるとは。
まだまだJythonも使えそうだ。

同じタグの記事
同じカテゴリの記事

pathlib.Pathを調べる

pathlib.Pathを調べる

最近はPython3.4以降の環境でスクリプトを作っているため、osモジュールからpathlibモジュールを利用するように方針を変えている。
そこで、pathlib.Pathの使えそうなメソッドを調べることにした。

まずはimport

1
from pathlib import Path

メインクラスをimportする。

ディレクトリ内のファイル・ディレクトリを取得する。

1
2
3
p = Path('C:/Windows')
for path in p.iterdir():
    print(path)

iterdir()で返却されるのはPathのイテレータ。なので、さまざまなpathのメソッドを呼び出すことができる。

ディレクトリかファイルかを判定する。

1
2
3
4
5
6
7
8
p = Path('C:\', 'Windows')
for path in p.iterdir():
    if path.is_dir():
        print('
Directory:{}'.format(path))
    elif path.is_file():
        print('
File     :{}'.format(path))
    else:
        print('
?        :{}'.format(path))

pathはPathクラスのインスタンスなので、そのメソッドを呼び出せばよい。
なお、Path()の引数は、os.path.joinのように、カンマ区切りで指定しても良い。

パスの追加

1
2
3
4
p = Path('C:\', 'Windows')
q = p / '
System32'
for path in q.iterdir():
    print(path)

演算子’/’がオーバーロードされている。カッコいい。ただ、あまり使うことはない気がする。

ファイルを開く

1
2
3
4
p = Path('C:\', 'Windows', 'System32', 'drivers', 'etc', 'hosts')
with p.open(encoding='
UTF-8') as r:
    for line in r:
        print(line)

pathインスタンスからそのままファイルオープンすることができる。エンコーディングも指定できる。便利。

ドライブ名の取得、パスの分解

1
2
3
p = Path('C:\', 'Windows', 'System32', 'drivers', 'etc', 'hosts')
print(p.drive)
print(p.parts)

ドライブ名はWindows独自。
partsも何かに使えるかな?partsに対してinして、フィルタする?

parentsとparent

1
2
3
4
5
p = Path('C:\', 'Windows', 'System32', 'drivers', 'etc', 'hosts')
print(p.parent)
print(p.parents[0])
print(p.parents[1])
print(p.parents[2])

parentは親、parentsは指定階層上の親。2階層上や3階層上の親が欲しい場合もあるかも。

名前、拡張子、拡張子なしの名前

1
2
3
4
5
p = Path('C:\', 'var', 'log', 'accesslog.tar.gz')
print(p.name)
print(p.suffix)
print(p.suffixes)
print(p.stem)

nameはファイル名またはディレクトリ名(accesslog.tar.gz)。
suffixは末端の拡張子(.gz)。
suffixesは拡張子のリスト([.tar, .gz])。
stemは拡張子(suffix)を除いたファイル名(accesslog.tar)。

カレントディレクトリ、ホームディレクトリ

1
2
print(Path.cwd())
print(Path.home())

地味だけど便利そう。
※ home()はPython3.5以降。

ファイルステータス

1
2
3
4
p = Path('C:\', 'Windows', 'System32', 'drivers', 'etc', 'hosts')
stat = p.stat()
print(stat.st_size)
print(stat.st_mtime)

os.stat()と同様の結果を得られる。ファイルサイズや作成日、更新日など。

パスが存在するかどうか

1
2
3
4
5
p = Path('C:\', 'Windows', 'System32')
if p.exists():
    print('
exists')
else:
    print('
not exists')

ファイル出力前に使えそう。
ファイル入力前はis_file()がよさそう。

再帰的なディレクトリ走査

1
2
3
4
for path in Path('C:\', 'Windows', 'System32').glob('**/*.dll'):
    print(path)
for path in Path('
C:\', 'Windows', 'System32').rglob('*.dll'):
    print(path)

glob()の引数の’**/’が再帰を表す。単一階層であれば’*.dll’を指定する。これは使えそう。
rglob()は常に再帰する。どちらでも覚えやすい方を使えばよいと思う。

ディレクトリ作成

1
2
p = Path('F:/work1/work2/work3')
p.mkdir(parents=True)

ディレクトリを作成する。parent=Trueを指定することで、再帰的にディレクトリを作成してくれる。osモジュールのos.makedirs()の様に動く。
これは便利。

単純なファイルの読み書き ※Python3.5以降

1
2
3
4
p = Path('C:\', 'Windows', 'System32', 'drivers', 'etc', 'hosts')
text = p.read_text(encoding='
UTF-8')
p = Path('
F:\', 'temp.txt')
p.write_text(text, encoding='
UTF-8')

read_text()でファイル全体を読み込み、write_text()で引数の文字列を一気に書き出す。ファイルサイズによっては使えそう。
※ Python3.5以降

名前変更

1
2
p = Path('F:\\temp.txt')
p.replace('F:\\work\new.txt')

replace()でファイル名を変更できる。途中のディレクトリを勝手に作ってくれることはないので、そこはあらかじめ準備しておく。

touch

1
2
p = Path('F:\\temp2.txt')
p.touch()

シェルコマンドのtouchと同様。現在日時で0バイトファイルを作成する。

まとめ

なかなか良いモジュールだ。
再帰走査ができるし、そのままエンコードを指定して読み込むこともできるし、足りないことの方が見つからない。これからはどんどん使っていこう。もうPython2.7には戻れない。

同じタグの記事
同じカテゴリの記事

macOS Mojaveに更新したらgitコマンドが使えなくなった

macOS Mojaveに更新したらgitコマンドが使えなくなった。

macOSを10.14 Mojaveに更新した。
gitコマンドがエラーになった。

症状:git pullできない

1
2
MacBookAir:program user$ git pull
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun

原因:Command Line Toolsが動作しなくなっていた

次のコマンドを実行し、Command Line Toolsをインストールしたら、今まで通り動くようになった。

1
2
MacBookAir:program user$ xcode-select --install
xcode-select: note: install requested for command line developer tools

まとめ

High Sierraに更新したときも同じ症状になっていた。
すっかり忘れていた。
次は、High Mojave(Mojave Max?)のときだろうか。

同じタグの記事
同じカテゴリの記事

jQueryで部分一致検索

jQueryで部分一致検索

誰かの作った難解なプログラムがある。サーバサイドは手がつけられない。
クライアントサイドはjqueryが利用されている。こちらはなんとかなりそう。

クリックイベントが設定されたelementがあり、その同レベルにinputタグがある。そのinputタグを辿りたい。

parent().find()

同レベルなので、親(Parent)を起点に検索(Find)する。

1
$(this).parent().find(xxx)

selector “input[name$=’.lastName’]”

同レベルにある下記の値を取得したい。

1
<input type="text" name="list[0].lastName" value="Doe" />
1
var lastName = $(this).parent().find("input[name$='.lastName']").val()

取得できた。
“$=”は後方一致として動作する。
ちなみに、前方一致は”^=”。
正規表現のようだ。
部分一致は”*=”。これは正規表現ではない。

まとめ

javascriptのみでプログラムを改修することができた。
jquery便利だ。

同じタグの記事
同じカテゴリの記事

macOSをMojaveに更新した。スクリプト実行環境のバージョンは変わったか

macOSをMojaveに更新した。スクリプト実行環境のバージョンは変わったか

Python

Mojave

1
2
3
Python 2.7.10 (default, Aug 17 2018, 17:41:52)
[GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.0.42)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

High Sierra

1
2
3
Python 2.7.10 (default, Oct  6 2017, 22:29:07)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

Pythonのバージョンは変更なし。
コンパイラのバージョンは上がっている。

perl

Mojave

1
2
3
4
This is perl 5, version 18, subversion 2 (v5.18.2) built for darwin-thread-multi-2level
(with 2 registered patches, see perl -V for more detail)

Copyright 1987-2013, Larry Wall

High Sierra

1
2
3
4
This is perl 5, version 18, subversion 2 (v5.18.2) built for darwin-thread-multi-2level
(with 2 registered patches, see perl -V for more detail)

Copyright 1987-2013, Larry Wall

perlのバージョンは変わらない。

PHP

Mojave

1
2
3
PHP 7.1.19 (cli) (built: Aug 17 2018 18:03:17) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies

High Sierra

1
2
3
PHP 7.1.16 (cli) (built: Mar 31 2018 02:59:59) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies

細かいバージョンが上がっている。

Ruby

Mojave

1
ruby 2.3.7p456 (2018-03-28 revision 63024) [universal.x86_64-darwin18]

High Sierra

1
ruby 2.3.7p456 (2018-03-28 revision 63024) [universal.x86_64-darwin17]

Rubyのバージョンは変わらない。

sqlite3

Mojave

1
SQLite version 3.24.0 2018-06-04 14:10:15

High Sierra

1
SQLite version 3.19.3 2017-06-27 16:48:08

細かいバージョンが上がっている。

まとめ

今回もPythonのバージョンアップはなかった。
macOSの何らかのプログラムがPython2に依存しているのだろうか。

同じタグの記事
同じカテゴリの記事

Pythonでリスト、タプルの重複除去

Pythonでリスト、タプルの重複除去

特殊なデータストアからデータを抽出し、返却するバッチ処理がある。そのバッチ処理は定期実行され、キューイングはXMLファイル行われる。
同じ時間の処理で、返却先が異なるが同じデータへのリクエストが来ることがある。
同じデータをデータストアに何度もアクセスしたくない。リクエストをListにため込んでから、重複を除去して問い合わせを行う。
Listの重複をどのように行うか。

setを利用する

1
2
3
4
5
6
7
work_list = []
for x in range(10):
    work_list.append(x % 3)
print(work_list)

target_set = set(work_list)
print(target_set)

このプログラムを実行すと、work_listは

1
[0, 1, 2, 0, 1, 2, 0, 1, 2, 0]

target_setは

1
{0, 1, 2}

と出力される。

まとめ

リストの重複除去が簡単に行えた。
しかし、順序は保証されないようなので、順序が重要な場合は自身でイテレートして重複を除去する必要がある。
または、そもそもwork_listにappendする前に、if xx not in work_list:でリストに含まれないことを確認してからappendすればよい。ここはお好みで。

同じタグの記事
同じカテゴリの記事

Linuxコマンドを利用してログを集計する

Linuxコマンドを利用してログを集計する

相変わらず、ログを集計している。
今回は特定の処理を呼ばれたかどうかを集計するだけなので、Pythonスクリプトを作成する必要もない。
日別に何件発生しているのか、集計しようと思う。

最初に結果

1
find . -name 'app.log.20*' | xargs grep -h "my.Program" | cut -b 1-10 | sort | uniq -c | awk '{print $2"\t"$1}' > res.txt

これで日別の件数が取得できた。
パイプで繋がれた、それぞれのコマンドにどのような役割があるのか、以下で説明する。

find

1
find . -name 'app.log.20*'

ログファイルはapp.log.yyyymmddの形式で出力されている。ログディレクトリに保存されているのだが、当月、当年、それより前でディレクトリ構成が異なる。また、異なるシステムのログファイルも含まれているため、事前にファイルの選別が必要になる。それでfindを利用している。

xargs grep

1
xargs grep -h "my.Program"

findの結果をxargsを利用してgrepに通している。
grepでは、見つけたログファイルの中に、特定の文字列(チェック対象のプログラム名)が含まれている行を抽出している。
-hオプションは、grep結果にファイル名が出力されることを抑制するために指定している。

cut

1
cut -b 1-10

grep結果の先頭10バイトは年月日がYYYY/MM/DD形式で書かれている。そこだけを抽出した。

sort

1
sort

次の処理で日別の件数を求めるが、そのコマンドは集計キーが並んでいる必要がある。そのためにcutの結果をsortした。

uniq

1
uniq -c

uniqコマンドで年月日ごとの出力行数をカウントした。
-cオプションが集計数を表示するオプション。
-cオプションが指定されないと、重複行の除去のみ行われる。

awk

1
awk '{print $2"\t"$1}'

uniqの出力結果は”集計件数 集計項目”の順番で出力される。今回の例では下記のように出力される。

1
2
   100 2018/09/01
    98 2018/09/02

しかし、これだとExcelに張り付けたときに見栄えが悪いので、”年月日{タブ}件数”の様に出力順を入れ替えた。

>

1
> res.txt

これまでの処理結果をres.txtに保存した。

まとめ

ここまでくれば、この結果をテキストエディタで開きコピー、Excelの空のシートに張り付け、貼り付け結果のデータをテーブルに変換し、ピボットグラフを作れば集計は終わりだ。

簡単だし、結構なスピードで集計が完了した。
たまにはコマンドも良い。

同じタグの記事
同じカテゴリの記事

Pythonで文字列が含まれているかどうかを調べる

Pythonで文字列が含まれているかどうかを調べる

あいかわらず、ログファイルを集計している。
ログファイルに特定の文字が現れる行の行数を数えたい。

文字が含まれているかどうか

strのfindを使うと、他の言語のindexOfの様に位置を出現個所の位置を返してくれるようだ。

1
2
3
line = 'test message'
print(line.find('mes'))
print(line.find('mec'))

上記の例だと、最初が5、次が-1が返る。
-1より大きいかどうかを判断すれば文字が含まれるかどうかをチェックできる。
しかし、今回は位置は必要ない。
そういう場合は、配列に含まれているかどうかと同様に in を使えばよい。

1
2
3
line = 'test message'
print('mes' in line)
print('mec' in line)

上記の例だと、最初がTrue、次がFalseが返る。
スマート。
そして、統一感がある。

まとめ

inで含まれているかどうかが、配列でもディクショナリでも文字列でも扱えるところは統一感があって素晴らしい。
ちなみに、Kotlinであればcontainsがそれにあたるのだろう。

同じタグの記事
同じカテゴリの記事