default eye-catch image.

論理値、論理演算子、自己代入

真/偽 TrueClassのインスタンスがtrue、 FalseClassのインスタンスがfalse。 NilClassのインスタンスがnil。 true.class # TrueClass false.class # FalseClass falseとnilのみ偽として評価される。 falseとnil以外は全て真として評価。 この動きにより、変数に値が入っているかどうかは、 nilと比較する必要はなく変数を評価するだけで良い。 PHPのように変数に値が入っていることをチェックする必要はない。 if文 オーソドックスなif文。 compare = true if compare then \"OK\" end if文は式なのでif文を評価すると値が返る。 評価値はif式内で最後に評価された値となる。 a = if true 1 end p a # 1 後置ifという構文。簡単にコードが短くなって便利そう。だが...、 後置ifがfalseの場合でも、変数自体は確保される。が値が入らない。 意図せず変数がnilになるコードを書く可能性がある。 未定義の変数と、確保済みだが値なしの変数は明確に異なる。 a = 1 if true p a # 1 b = 1 if false p b # nil もし偽だったら、を書きたい場合はunless構文を使う。 unless false p 1 # 1 end 単項演算子?は使える。 n = (a==10) ? true : false 論理演算子 論理演算子は最後に評価したオペランドの値を返す。 評価結果(true,false)を返さない。 x = nil && 4 # nil y = 1 || 2 # 1 自己代入 変数が真でない場合に限りその変数に値を代入する自己代入。 これは、論理演算の際どい評価順序を利用していて、何故そうなるかは深い深い海の底にある。 z = z || 1 # 1 z ||= 1 # 1 zが真でない場合、つまりzがfalseかnilの場合に、 論理和演算子の右側のオペランドである1の評価結果(=1)がzに代入される。 未確保・未定義の変数の評価結果はnilなので、 未定義・未確保の場合に限り初期値を入れることができる。 z = 10 z = z || 1 # 10 &&とand、||とor、!とnot &&とand、||とor、!とnotという風に、同じ意味の論理演算子が対で用意されている。 それぞれ評価時の優先順位が異なる。(以下のようになる) p x && z # = p (x && z) p x and z # = (p x) and z

default eye-catch image.

整数リテラルとメソッド

[arst_toc tag=\"h3\"] 命名規則1.ローカル変数 変数名により用途が決まるので理解が必要。 資格系なら\"不適切な変数名\"を見抜けるかが大事。 ローカル変数は、代入が行われたブロックまたはメソッドの中だけで有効なスコープの変数。 ローカル変数は以下から構成される。ただし数字は先に来ない。 アンダースコア「_」 英数字 以下は変数名としてN.G. # アンダースコア以外の記号「-」が使われている variable-1 # これも safe? # 先頭が数値 100_or_1000 # 定数 VARIABLE 予約後を変数として再定義することはできない。 関数内ならスコープ外のローカル変数を参照すると例外。 kuma=20 def hoge(x,y) kuma end スコープ内で定義されているが評価されていない変数を参照するとnil。 def hoge(x,y) kuma = x + y if x > 10 kuma end > hoge 20,30 => 50 > hoge 5,10 => nil 命名規則2.グローバル変数 スコープに関係なくどこからでも参照できる変数。 構成する文字はローカル変数と同じ。ただし先頭は「$」。 アンダースコア「_」 英数字 $global = 100 def fuga(a,b) $global end > fuga 10,20 => 100 リテラルの種類 Rubyのリテラルは以下。 数値 論理値 文字列 シンボル 配列 ハッシュ 範囲 正規表現 ハッシュ 数値リテラル 整数と浮動小数点を使える。符号、指数表記、基数指定が可能。 基数指定でありえない値を指定すると例外。 +100 -200 2e2 # 2 に10の2乗を掛ける => 20 5e-e # 5 に10の-3乗を掛ける => 0.05 0b10 # 2進数の10 => 2 0o10 # 8進数の10 => 8 0d10 # 10進数の10 => 10 0x10 # 16進数の10 => 16 0xfg # 16進数でgはNG 数値リテラル内で桁表現ができる。(ロケールが違うときはどうなるのだろうか?) 100_000 => 100000 有理数(Rational)、複素数(Complex)もリテラル。 有理数は既約になる。浮動小数点にしないで保持できる。 また、小数を既約分数に変換できる!(すごい過剰な感じがする...) 25/45r # (5/9) 3.14r # (157/50) 複素数は実数、虚数の指定を整数、小数を使って表現できる。 12i # (0+12i) 5.6i # (5+6i) 有理数、虚数をミックスすることもできる。 3.14ri # (0+(157/50)i) 数値クラス 数値クラスのインスタンスである。 一言に数値クラスといっても継承関係によって詳細化されている。 a = 100 a.class # Fixnum a.class.superclass # Integer a.class.superclass.superclass # Numeric 数値クラスに実装された演算子により、数値演算、比較演算を実行できるようになっている。 数値演算 代表的な2項演算子は一通り使える。 1+1 # 2 1-2 # -1 3*3 # 9 4/2 # 2 4%3 # 1 代表的な比較演算子も一通り使える。 1==1 # true 1!=5 # true 1=1 # true 怪しい演算子が用意されている。UFO演算子。 演算子の左が大きければ1、等しければ0、右が大きければ-1。 500 10 # 1 500 500 # 0 10 500 # -1 と書いてあるけど、オペランドがNumericの時の話であって、 一般には「正」「0」「負」の振り分けと考えた方が良さそう。 オペランドが比較不能な場合はnilだそうだ。 if文を使って3方分岐するときに使える。 compare = (hoge fuga) if compare == 0 # hogeとfugaが比較可能で等しいとき elseif compare > 0 # hogeとfugaが比較可能でhogeが大きいとき else # 上記以外 (比較可能でfugaが大きいときを含む) end Rubyにはインクリメント演算子、デクリメント演算子は存在しない。 ので代わりに自己代入演算子を使う。 a = 100 a += 20 # 120 a -= 30 # 90 a *= 2 # 180 数値クラスの演算子であることを意識した書き方をすると、 数値の加算を以下のように書ける。 a = 100 a .+(50) # 150 メソッド 最後に評価された値が返る。returnで返すとそこで評価が終了する。 returnを書かないと関数内を最後まで読んで何が最終評価か理解しないといけないから 明示的returnを推奨する人もいるが、無いコードも多数ある。資格系はreturn無しの様子。 def add(x,y) x+y end > add 10,20 30=> nil def predict(hoge) if (hoge) then \"OK\" else \"NG\" end end > predict false => \"NG\" 仮引数のデフォルト値を指定できる。指定した引数の数が足りない場合は例外。 def add(x,y=200) x+y end add 10 => 210 キーワード引数 仮引数に名前をつけることができる。 これによりメソッド実行時に引数としてハッシュオブジェクトを渡せるようになる。 def add(x:,y:) x+y end add (x:100,y:200) => 300 キーワード引数にない引数名を指定すると例外。 def add(x:,y:) x+y end add (x:100,z:200) # 例外 ただし、キーワード引数を定義したメソッドに任意の引数を渡すことができる。 def add(x:,y:,**z) p z x+y end add (x:100,y:200,z:300) # {z=>300} => 300

default eye-catch image.

vagrant(ubuntu/xenial64 vbox) ubuntu16にrbenv rubyをインストールするplaybook (ほぼ失敗作)

作ってみたがrbenv installにとても時間がかかるので現実的ではないと思う。 vagrantのように壊して作るのが前提ならrbenvでバージョンを切り替えられる必要はないから、 わざわざ毎回コンパイルすることはない気がする。 いずれapt-get installで直接インストールする方法を試してみる。 commonロール 実験の結果、ubuntu/xenial64 vboxに必要だったパッケージたちを入れるロール。 become: yes, become_method: sudo で実行。 --- - name: install packages apt: name=\"{{item}}\" state=present with_items: - gcc - make - libssl-dev - zlib1g-dev rbenv,rubyインストールロール ansible実行ユーザ(ubuntu)のホームディレクトリ以下にrbenvとrubyを入れるロール。 .profileに追加した内容を反映して次に進まないとエラーになる...->要改良 --- - name: retrieve the latest rbenv to ~/.rbenv git: repo=https://github.com/sstephenson/rbenv.git dest=/home/{{user}}/.rbenv accept_hostkey=yes force=yes - name: retrieve the latest ruby-build plugin to ~/.rbenv/plugins/ruby-build git: repo=git://github.com/sstephenson/ruby-build.git dest=/home/{{user}}/.rbenv/plugins/ruby-build accept_hostkey=yes force=yes - name: add path to ~/.rbenv/bin lineinfile: dest=/home/{{user}}/.profile line=\'PATH=\"$HOME/.rbenv/bin:$PATH\"\' state=present create=yes - name: add path to ~/.rbenv/plugins/ruby-build/bin lineinfile: dest=/home/{{user}}/.profile line=\'PATH=\"$HOME/.rbenv/plugins/ruby-build/bin:$PATH\"\' state=present create=yes - name: add initial evaluation of rbenv init lineinfile: dest=/home/{{user}}/.profile line=\'eval \"$(rbenv init -)\"\' state=present create=yes - name: add gem lineinfile: dest=/home/{{user}}/.gemrc line=\"gem{{COLON}} --no-ri --no-rdoc\" state=present create=yes - name: rbenv install 2.4.1 shell: bash -lc \"rbenv install 2.4.1\" - name: rbenv global 2.4.1 shell: bash -lc \"rbenv global 2.4.1\" - name: gem install bundler shell: bash -lc \"gem install bundler\"

default eye-catch image.

PythonでAES EncryptしてPHPでAES Decryptできなかった話

標題の通りなのですが。AESなんて枯れてるんだから鍵長と暗号モードを合わせれば出来るだろうと、軽く見積もってました。結果、無茶苦茶頑張ってみましたが出来ませんでした! 結論から先に書くと、以下の方法で逃げました。 PythonでEncrypt/Decrypt Classを書く Python側からは上記のClassをそのまま使う 上記のClassを叩くPythonスクリプトを書き、PHPからシェル経由でそのスクリプトを実行する。 もっと頑張れば道が見つかったかもしれませんが、本当にPython/PHPをクロスして暗号化/復号の対ができるのか心配になって、これに落ち着きました。 出来ない理由.. 正直出来ない理由もハッキリしません。 だいたいどちらでも以下ぐらいは設定できるものなのですが、以下を合わせたぐらいでは片方で暗号化したものを復号することができません。 鍵長=256bit Cypher Algorythm=Rijndael 暗号モード=ECB orCBC まともな暗号処理をするには暗号モードにECBは使えずInitialVector(IV)を与える必要があるのですが、乱数からIVを生成する箇所の共通性が怪しかったり、Python側では共通鍵の鍵長にAPIで制限がかかるものの、PHPでは任意に指定できたり、本当に実装すると突っ込みどころ満載になります。 Pythonのコードはだいたい以下のような感じになります(IVを共有するためにダイジェストにIVを含んでいるのは本質的でないので除いてみてください)。 PythonのCrypto.Cipherは Encryptした結果を自力でPaddingしてBase64エンコードしてますが、PHPのmdecryptはいきなりPrintableな文字列を要求します。普通に考えて、PHPのmdecryptがBase64デコードして同じようにPaddingを取り除くのを期待するのはナンセンスでしょ。 import base64 from Crypto import Random from Crypto.Cipher import AES class AESCipher(object): def __init__(self, key, block_size=32): self.bs = block_size if len(key) >= len(str(block_size)): self.key = key[:block_size] else: self.key = self._pad(key) def encrypt(self, raw): raw = self._pad(raw) iv = Random.new().read(AES.block_size) cipher = AES.new(self.key, AES.MODE_CBC, iv) return base64.b64encode(iv + cipher.encrypt(raw)) def decrypt(self, enc): enc = base64.b64decode(enc) iv = enc[:AES.block_size] cipher = AES.new(self.key, AES.MODE_CBC, iv) return self._unpad(cipher.decrypt(enc[AES.block_size:])) def _pad(self, s): return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs) def _unpad(self, s): return s[:-ord(s[len(s)-1:])] 気付いたこと 何か勘違いしているかもしれませんが、早々に別の道に進みました。

default eye-catch image.

実践 PSR-4 クラスをspl_autoloaderを使ってautoloadしてみる最も簡単なサンプル

PSR-4の一次情報を読んだことだし、現在の理解でPSR-4 Autoloadに対応したクラスを作成し実際にAutoloadしてみる。composerもPSR-4に対応しているが、まずはPHP-Figがサンプルとして公開しているspl_autoloaderを使った例を試すことにする。 仕様は以下の通り。 Fully qualified class name ikutyexamplePsr4HelloWorld Namespace Prefix ikutyexamplePsr4 Base Directory ./src/ikuty/example/Psr4 Resulting file path ./src/ikuty/example/Psr4/helloworld.php サンプルクラスの作成 ./src/ikuty/example/Psr4/helloworld.phpを以下の通り作成する。 $ pwd ./src/ikuty/example/Psr4 vi helloworld.php <?php namespace ikutyexamplePsr4; class HelloWorld { public function __construct() { echo \"Hello World!\"; } public function say() { echo \"Hello World!\"; } } 呼出側の作成(PSR-0的) PHP Figにあるクロージャ版spl_autoloaderを使った実装例を試してみる。 ikutyexamplePsr4HelloWorldをnew()すると、spl_autoload_registerで登録したクロージャが評価される。 なお、名前空間の深さとBaseDirectoryの深さ等しくしている意味でPSR-0的なサンプル。 [sample.php] <?php 2 spl_autoload_register(function ($class){ 3 4 //project-specific namespace prefix 5 $prefix = \'ikuty\\example\\Psr4\\\'; 6 7 //base directory for the namespace prefix 8 $base_dir = __DIR__ . \'/src/ikuty/example/Psr4/\'; 9 10 //does the class use the namespace prefix? 11 $len = strlen($prefix); 12 if (strncmp($prefix, $class, $len) !== 0){ 13 // no, move to the next registerd autoloader 14 return; 15 } 16 17 //get the relative class name 18 $relative_class = substr($class, $len); 19 20 //replace the namespace prefix with the base directory, replace namespace 21 //separators with directory separators in the relative class name, append 22 //with .php 23 $file = $base_dir . str_replace(\'\\\',\'/\', $relative_class).\'.php\'; 24 25 //if the file exists, require it 26 if (file_exists($file)) { 27 require $file; 28 } 29 30 }); 31 32 $example = new ikutyexamplePsr4HelloWorld(); 33 $example->say(); 名前空間プレフィックスとBaseDirectoryの紐づけは結局人力でやっている。「名前空間プレフィックス」と「クラス名」の間にある「サブ名前空間」を読み飛ばしている。名前空間プレフィックスに続く「サブ名前空間」分をクラス側が自由に使えるところが興味深い。 実行結果 実行してみる。実行結果から分かりにくくて恐縮だが、new()してもHello World!は出力されず、say()メソッドを実行したときにHello World!が2回表示された。late-binding的な感じ。 $ php sample.php Hello World!Hello World! 名前空間の深さと関係なくBaseDirectoryを設定する(PSR-4的) 例えば、ikutyexamplePsr4HelloWorldの名前空間プレフィックスikutyexamplePsr4をBaseDirectory ./ikuty-example-psr4 に紐づければ、名前空間がどれだけ深くてもデプロイは影響を受けない。 Fully qualified class name ikutyexamplePsr4HelloWorld Namespace Prefix ikutyexamplePsr4 Base Directory ./src/ikuty-example-Psr4 Resulting file path ./src/ikuty-example-Psr4/helloworld.php <?php 2 spl_autoload_register(function ($class){ 3 4 //project-specific namespace prefix 5 $prefix = \'ikuty\\example\\Psr4\\\'; 6 7 //base directory for the namespace prefix 8 //$base_dir = __DIR__ . \'/src/ikuty/example/Psr4/\'; 9 $base_dir = __DIR__ . \'/src-ikuty-example-psr4/\'; 10 11 12 //does the class use the namespace prefix? 13 $len = strlen($prefix); 14 if (strncmp($prefix, $class, $len) !== 0){ 15 // no, move to the next registerd autoloader 16 return; 17 } 18 19 //get the relative class name 20 $relative_class = substr($class, $len); 21 22 //replace the namespace prefix with the base directory, replace namespace 23 //separators with directory separators in the relative class name, append 24 //with .php 25 $file = $base_dir . str_replace(\'\\\',\'/\', $relative_class).\'.php\'; 26 27 //if the file exists, require it 28 if (file_exists($file)) { 29 require $file; 30 } 31 32 }); 33 34 $example = new ikutyexamplePsr4HelloWorld(); 35 $example->say(); 結論 PHP-Figがサンプルとして提供しているspl_autoloader(クロージャ版)をお試し実装してみた。 PSR-4は名前空間プレフィックスのベースディレクトリの関連を記述する仕様であり、ベースディレクトリの物理的な配置が名前空間プレフィックスに直接影響を受けない。 ベースディレクトリが深くならなくて良い

default eye-catch image.

PSR-4 の理解

What\'s PSR-4 ? そもそもPSRって何の略だろうと調べたがそこから出てこなかった。 ↓なんじゃないか、という意見あり。 PHP Standard Recommendation PHP Specification Request カテゴリ毎に数字が割り当てられており他にも以下が存在する。 PSR-0 Autoloading PSR-1 Basic Coding Standard PSR-2 Coding Style Guide PSR-3 Logger Interface PSR-4 Improved Autoloading PSR-6 Chaching Interface PSR-7 HTTP Message Interface PHP-FIGという団体で取りまとめられている。http://www.php-fig.org/ PSR-4 それでは早速一次情報から漁ってみる。どのパスにどのクラスを配置するのか仕様を決めたいというのが根っこにある。決まりがあればクラスを使う側が楽だから。楽に使ってもらえるよう配布手段に規約を設ける。PSR-0(等?)と互換性がある。(PSR-0以外にもこういう決まりがあるのか?) This PSR describes a specification for autoloading classes from file paths. It is fully interoperable, and can be used in addition to any other autoloading specification, including PSR-0. This PSR also describes where to place files that will be autoloaded according to the specification. 仕様 言葉遊び ドキュメント内では\"class\"は class,interfaces,traits,それに似た構造を指すそうだ。あくまでも外部から使用する対象と配置に関する仕様だよ、ということだ。対象は何でも良い。 The term \"class\" refers to classes, interfaces, traits, and other similar structures. 完全修飾クラス名 完全修飾クラス名は次のような形式となるそうだ。 A fully qualified class name has the following form: \<NamespaceName>(<SubNamespaceNames>)*<ClassName> いくつか決まり事がある。 The fully qualified class name MUST have a top-level namespace name, also known as a \"vendor namespace\". 完全修飾クラス名にはベンダーを表すユニークな名前空間が入っていないといけない。 NamespaceNameが一意なのか、NamespaceNameとSubNamespaceNamesの合わせ技で一意なのか不明。 GitHubに上がってるのを見るとNamespaceNameだけで表現しているようだ。「トップレベル」って「一番最初=NamespaceName」のことか?? The fully qualified class name MAY have one or more sub-namespace names. 補助的に名前空間を複数追加しても良い。 階層構造を持った複雑な名前空間も定義できるということ。 The fully qualified class name MUST have a terminating class name. 完全修飾クラス名の最後はクラス名でなければならない。 Underscores have no special meaning in any portion of the fully qualified class name. アンスコは特別な意味を持たない。 アンスコを前後の識別子の接続子のように使うフレームワークが多いからね。 アンスコは単なる文字。 Alphabetic characters in the fully qualified class name MAY be any combination of lower case and upper case. 大文字小文字の任意の組み合わせで良い。 大文字小文字に意味を持たせるフレームワークが多いからね。 All class names MUST be referenced in a case-sensitive fashion. 大文字小文字を区別する。 ファイルをロードする側の決まりごと A contiguous series of one or more leading namespace and sub-namespace names, not including the leading namespace separator, in the fully qualified class name (a \"namespace prefix\") corresponds to at least one \"base directory\". NamespaceNameといくつかのSubNamespaceNameを「名前空間プレフィックス」と呼ぶ SubNamespaceNameが複数個あった場合その全てが「名前空間プレフィックス」になるとは読めない。 完全修飾クラス名とは「名前空間プレフィックス」+(「サブ名前空間」)+「クラス名」となる。 「名前空間プレフィックス」がディレクトリ名と対応している必要がある。と書いてあるがサンプルの「BaseDirectory」が名前空間プレフィックスと全然違う。意味不明。 The contiguous sub-namespace names after the \"namespace prefix\" correspond to a subdirectory within a \"base directory\", in which the namespace separators represent directory separators. The subdirectory name MUST match the case of the sub-namespace names. 名前空間プレフィックスに続くサブ名前空間が、BaseDirectoryに続くサブディレクトリに対応する。 サブ名前空間とサブディレクトリの大文字小文字は一致している必要がある。 The terminating class name corresponds to a file name ending in .php. The file name MUST match the case of the terminating class name. 終端のクラス名は、大文字小文字が一致するphpファイルと対応する。 例 PSR-4の例。やはり、どうも規則性が見えない。 FULLY QUALIFIED CLASS NAME NAMESPACE PREFIX BASE DIRECTORY RESULTING FILE PATH AcmeLogWriterFile_Writer AcmeLogWriter ./acme-log-writer/lib/ ./acme-log-writer/lib/File_Writer.php AuraWebResponseStatus AuraWeb /path/to/aura-web/src/ /path/to/aura-web/src/Response/Status.php SymfonyCoreRequest SymfonyCore ./vendor/Symfony/Core/ ./vendor/Symfony/Core/Request.php ZendAcl Zend /usr/includes/Zend/ /usr/includes/Zend/Acl.php 全然規則性が見えないぞ? 全然しっくりこないのでさらに調べてみた。COMPOSERがだいぶ前にPSR-4に対応したらしいのでAUTOLOADの補完ルールを色分けした。を参考にさせて頂きました。 FULLY QUALIFIED CLASS NAME NAMESPACE PREFIX BASE DIRECTORY RESULTING FILE PATH AcmeLogWriterFile_Writer AcmeLogWriter ./acme-log-writer/lib/ ./acme-log-writer/lib/File_Writer.php AuraWebResponseStatus AuraWeb /path/to/aura-web/src/ /path/to/aura-web/src/Response/Status.php SymfonyCoreRequest SymfonyCore ./vendor/Symfony/Core/ ./vendor/Symfony/Core/Request.php ZendAcl Zend /usr/includes/Zend/ /usr/includes/Zend/Acl.php 訳にも書いたが、全てのサブ名前空間が名前空間プレフィックスに含まれる訳ではないことに注意。名前空間プレフィックスに含まれなかったサブ名前空間が突然ファイルパスに出現したりする。 サブ名前空間とBaseDirectoryの規則性について、サブ名前空間をハイフンで区切った一つのディレクトリと対応させる場合もあるし、階層構造まで一致させる場合もある。名前空間プレフィックスとBase Directoryの関係性は割と柔軟。