カテゴリー別アーカイブ: program

cygwinのファイルアクセスが遅い件:解決編

もうmagit無しではemacsでコーディングできない体になってしまった。 さらに便利を求めて git-gutter-fringe+ をインストールしたところ、 Macではもう最高の使い心地。

だけども。 これをCygwinとntemacsで使うと、しょっちゅうプチフリーズしてしまう。 Cygwinのファイルアクセスが異常に遅いせいなのだけれど、 仕事上Cygwin環境は必須だし、git-gutterは手放したくないし。

いくら便利でも、作業中に30秒も固まられると、さすがに我慢できない。 いい加減、ちゃんとCygwinに対策をしなければ…

と言う訳で。

Cygwinの起動やファイルアクセスが遅くて怪しい場合に

CygwinのFAQサイト を検索してみた。

以下、Cygwinのページから引用。

4.2. Starting a new terminal window is slow. What’s going on?

There are many possible causes for this.

~snip~

For almost all its lifetime, Cygwin has used Unix-like /etc/passwd and /etc/group files to mirror the contents of the Windows SAM and AD databases. Although these files can still be used, since Cygwin 1.7.34, new installations now use the SAM/AD databases directly.

To switch to the new method, move these two files out of the way and restart the Cygwin terminal. That runs Cygwin in its new default mode.

~snip~

For the AD case, it can be slower than the old method, since it is trading a local file read for a network request. Version 1.7.35 will reduce the number of AD server requests the DLL makes relative to 1.7.34, with the consequence that you will now have to alter /etc/nsswitch.conf in order to change your Cygwin home directory, instead of being able to change it from the AD configuration.

If you are still experiencing very slow shell startups, there are a number of other things you can look into:

One common cause of slow Cygwin Terminal starts is a bad DNS setup. This particularly affects AD clients, but there may be other things in your Cygwin startup that depend on getting fast answers back from a network server.

~snip~

Another cause for AD client system is slow DC replies, commonly observed in configurations with remote DC access. The Cygwin DLL queries information about every group you’re in to populate the local cache on startup. You may speed up this process a little by caching your own information in local files. Run these commands in a Cygwin terminal with write access to /etc:

getent passwd $(id -u) > /etc/passwd getent group $(id -G) > /etc/group Also, set /etc/nsswitch.conf as follows:

passwd: files db group: files db

~snip~

Either in addition to the previous item or instead of it, you can run cygserver as a local caching service to speed up DC requests.

~snip~

A less preferable option is to create a static read-only cache of the authentication data. This is the old-fashioned method of making Cygwin integrate with AD, the only method available in releases before 1.7.34. To do this, run mkpasswd and mkgroup, then put the following into /etc/nsswitch.conf to make Cygwin treat these files as the only sources of user and group information:

passwd: files group: files

~snip~

If none of the above helps, the best troubleshooting method is to run your startup scripts in debug mode. Right-click your Cygwin Terminal

~snip~

4.3. Why is Cygwin suddenly so slow?

If suddenly every command takes a very long time, then something is probably attempting to access a network share. You may have the obsolete //c notation in your PATH or startup files. Using //c means to contact the network server c, which will slow things down tremendously if it does not exist.

要するに、ドメインで使っている会社のPCで遅くなる原因は。。。

  1. cygwinを 1.7.35 以降の最近のバージョンにする (古いのは遅い)
  2. DNSのIPアドレスが間違っていると、長い待ちがおこる
  3. ドメインじゃないなら、 /etc/passwd と /etc/group を消すと良いかも(知れない)
  4. ドメインなら、ドメインコントローラの返事が遅いのかも
    • その場合、passwd/group をキャッシュして高速化できる
    • cygserverでドメンインキャッシュサーバをたててみても良いぞ
    • そもそもドメインにアクセスするの辞めちゃえば? (ADが更新しても知らんけど)
  5. それでもダメならデバッグモードで起動してみな
  6. ひょっとして ‘//c’ とか書いてない?

DNSが関係しているのは分かっていたけど、 会社のドメインコントローラが遅いとは疑っていなかった。 Windowsでは困ったことないし。

でもやってみよう。

まずはバージョン確認

以下のどちらかで確認できる。

uname -a
cygcheck -c cygwin

2.2.0 だったので、問題なし。

/etc/passwd と /etc/group の削除

cygwinでドメインに関係するような事はしないし、 むしろ悪さしそうなので、まず削除して様子をみてみた。

数時間使ってみて、酷いフリーズは経験しなかったけれど、 プチフリーズが解決したかと言うと、ちょっと分からない。

AD情報のキャッシュ化

ドメインの情報を削除するのも危険な気がしたので、 一応キャッシュしておいて、様子をみてみた。

ドメイン情報のキャッシュは、こうしてとれる。

getent passwd $(id -u) > /etc/passwd
getent group $(id -G) > /etc/group

その後、 /etc/nsswitch.conf を編集して、 ADにアクセスするより先にキャッシュ(files)を見るように変更する。

passwd: files db
group:  files db

正直、これも良くなったのか悪くなったのか分からない。

そもそもドメイン情報を使わないようにする

いくつか試してみた結果、 /etc/passwd と /etc/group を削除してしまうことにした。

実はこの状態でも、ドメインでアクセス管理しているネットワークサーバの ファイルにアクセスできたのだった。しかも今迄よりもサクサクと。(汗)

まだ、たまにフリーズはするものの (キャッシュはあった方が良いのかも知れない)、 全体的にファイルアクセスが軽快になった。

無くて良いものは、無い方が良い。 この状態で、またしばらく使ってみようと思う。

Blenderで半田とガラスの素材を作って、それっぽくレンダリングしてみた結果

以下の手順で、pythonだけで作ったポリゴンをBlenderでレンダリングしてみた。

  1. pythonとmatplotlibでポリンゴンデータを自作する
  2. meshデータを作る
  3. データオブジェクトを作る
  4. データオブジェクトをBlenderに登録する
  5. 自作した頂点情報と平面情報を、meshに登録して更新する
  6. それっぽいマテリアルを作ってレンダリングする

これで、そこそこ満足な結果にはなるのだけど。

  • matplotlibで表示したのと、微妙に位置がずれている
  • 頂点数が少ないのでカウカクしている
  • レンダリングした結果が、ステンドグラスっぽく見えない

微妙な位置ずれは3D Viewの時だけで、レンダリングには影響していない様なので、 とりあえず放置。

あとは、レンダリングの調整なので、Blenderの機能でアレコレ試してみる。

ポリンゴンを操作して半田(ガラスの境目)面の隙間を埋める

ガラスに沿って半田を再現するのは難しいので、 pythonの自作ポリゴンでは、厚みの無い平面で半田を表現していた。

ガラスの寸法は、半田が入るのを見越して小さめにしているので、 部品の境界に少し隙間が空いていた。

3D Viewでは目立たないけど、レンダリングすると隙間に筋が見えてしまう。

Blenderの SOLIDIFY Modifier を使って、この隙間を塞ぐ。

sm = obj.modifiers.new('Solidify', 'SOLIDIFY')
sm.thickness = 2

ポリンゴンを操作して半田の表面を丸める → 失敗

標準機能に、色々なModifiersがあるので試してみたけど、 所望の動作をする機能は見付からなかった。

Modifiersに合わせて、元の設計を少し変更した方が良さそうだ。

ちなみに、Modifiersを使うのはとても簡単。

solder.modifiers.new('modi', type='SUBSURF')
solder.modifiers.new('modi', type='SMOOTH')
solder.modifiers.new('modi', type='CAST')

とすれば良い。 気軽に色々な効果を試せるのが素晴しい。

マテリアルの質感の調整

ガラスの色、屈折率、透明感、テクスチャなどを色々設定。お好みで。

raytrace_mirror は、全部にかけるとレンダリングに時間がかかるので、 要所要所だけにしておくと良い。

# 素材:暗いガラス
glass2_mat = bpy.data.materials.new(""darkglass"")
glass2_mat.type = 'SURFACE'
glass2_mat.diffuse_color = (0, 0, 0.5)
glass2_mat.diffuse_intensity = 0.8
glass2_mat.use_transparency = True
glass2_mat.transparency_method = 'RAYTRACE'
glass2_mat.alpha = 0.55
glass2_mat.use_raytrace = True
glass2_mat.raytrace_transparency.ior = 1.56
glass2_mat.raytrace_transparency.falloff = 0.2
glass2_mat.raytrace_transparency.filter = 0.05
glass2_mat.raytrace_transparency.depth = 8
glass2_mat.raytrace_transparency.fresnel = 0.1
glass2_mat.raytrace_mirror.use = True
glass2_mat.raytrace_mirror.reflect_factor = 0.2
glass2_tex = bpy.data.textures.new(""marbleglass"", type='STUCCI')
glass2_tex.use_color_ramp = True
glass2_mat.texture_slots.add()
glass2_mat.texture_slots[0].texture = glass2_tex
casebox.data.materials.append(bpy.data.materials['darkglass'])

IORは、(Index Of Refraction, 屈折率)の意味らしい。 ぐぐった所、透明なものは大体こんな感じだった。 他の素材については、Blenderのページに沢山掲載されている。

他のパラメータの意味は

名称 意味 ガラスの参考値
Alpha 濁り具合 0.0
IOR 屈折率 1.5
Filter 色のつき具合 1
Depth 計算回数 8 最低でも4

細かい数字の大小は、あんまり気にしなくて良いみたいだ。

床に木目と影をつける

これまでで、そこそこガラスっぽさは出てきているのに、 何か不自然だと思ったら、床に影が出ていないからだ。

床も真っ白で、如何にもCGだし。

木目パターンを BEIZ Graphics さんの無料素材を有り難く使わせて頂いて、 以下の様に、マテリル>テクスチャ>画像という感じで紐付ける。

# 素材:床
floor_mat = bpy.data.materials.new(""woodfloor"")
floor_mat.type = 'SURFACE'
floor_mat.use_raytrace = True
floor_mat.use_transparency = False
floor_tex = bpy.data.textures.new(""woodfloor"", type='IMAGE')
floor_tex.image = bpy.data.images.load(filepath='./wood-texture_00008.jpg')
floor_mat.texture_slots.add()
floor_mat.texture_slots[0].texture = floor_tex
floor.data.materials.append(bpy.data.materials['woodfloor'])

影を綺麗につけるのには、ハマってしまった。

まず、影を追加する素材側(ここでは床)のマテリアルの影オプションで、 「半透明影の受諾」を有効にする。これは必須。

問題は照明側で、環境照明や間接照明を組み合わせると計算に時間がかかるし、 バランスがとり難い。

環境照明と間接照明はOFFにして、代りに、ランプの種類を 「ポイント」ではなく「サン」に変更すると良い感じになる。 計算時間がそんなに延びないので、扱い易い。

pythonでの設定は、こんな感じ。

# Lamp
lamp = bpy.data.objects['Lamp']
lamp.data.energy = 5
lamp.data.type = 'SUN'
lamp.location = (50, 50, 100)
lamp.rotation_euler = (0, 0, 0)
lamp.data.shadow_method = 'RAY_SHADOW'

背景に模様を追加して、移り込みを再現する

pro.foto さんから格好良い部屋の素材を有り難く使わせて頂いて、 背景を室内風に変更。

# 背景追加
world = bpy.data.worlds['World']
world_tex = bpy.data.textures.new(name=""BGTexture"", type='IMAGE')
world_tex.image = bpy.data.images.load(filepath='./sit0037-054.jpg')
world = bpy.context.scene.world
slot = world.texture_slots.add()
slot.texture = world_tex
slot.use_map_horizon = True
slot.horizon_factor = 1.0

結構良い感じに仕上がったので、ここで作業終了です。

完成したのがコチラ。いやぁ、Blenderすごいな。

AccessoryCase6Normal.png

ポリゴンを自作のpythonで書いたので、形状の変更が簡単

ポリゴンを自作のpythonで書いているので、高さや パネルの個数を変更するのが簡単。

パネル7枚で、高さを増したのはコチラ。

AccessoryCase7Tall.png

ステンドグラスの設計にはSketchUpとBlender、どっちが良い? あ、Pythonで書けば良いんじゃん

嫁さんの指令でステンドグラスの設計図を作ることに。

さて、どのCADを使おうか。
3DCADは、最後に仕事で使ってから、5年ぶりなのでサッパリ事情が分からない。
まぁ、思いつく3DCADは、個人で買えるような値段ではないんだけど。

調べると、オープンソースに、無償で使える3DCADがいくつか見付かった。
どうやら SketchUp と Blender が良さそうだ。

SketchUpは、Googleが扱っていた頃に少し、資料作成に使っていたけど、
今は、別の会社が買収して(基本的に)有償ソフトになっているらしい。

有償版の SketchUp Pro 以外に 無償版の SketchUp Make があるが、
Makeの方は機能制限([[http://www.alphacox.com/sketchup-pro/function/list/compare/][MakeとPro版の機能比較表]])が結構ある。

Blenderは、どちらかと言うと3DCGアニメーション向けの様だ。
こちらは無償。

スクリプト言語として、 SketchUpではRuby、 BlenderではPython が使える。

設計図を作る用途では SketchUp の方が向いていそうだけども、
2015年の無償版の情報があまりネット上で見付からない。

作った3DデータをHPで見せる場合には、 Blenderの方が便利そうだし。

そういう訳で、用途が違っていそうだが、Blenderを使うことにする。

まぁ、調べている間に、嫁さんの所望の図面は出来てしまったのだけれども。
結局、全部Pythonで書いてしまった。

こんな感じ。

acase_3d

acase_design

これを、もちっと格好良く見えるよう、 Blenderで作り直してみよう。

emacs org-mode で WordPress の記事を書きたい その2 TDDでプラグインを書いてみた結果…

PHPUnitでテストしながら実装してみたのでサーバに載せてみたところ、
Wordpressでは予定通りに動作しない。

ローカルでは問題なく動作したんだけれども。。。

# 動作結果の確認
Webサーバに転送してみたところ、うまく動作しない。
空行検出を含む一部の正規表現が、ローカルと違う動作結果を出していた。

原因は、PHPのバージョン違いか、文字コードか、WordPress固有の問題か?
それとも他の原因?

順に確認していこう。

# PHPのバージョン違い
ローカルのPHPは

PHP 5.5.27 (cli) (built: Jul 23 2015 00:21:59)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2015 Zend Technologies

サーバは 5.3 だったけれど、 5.5.19 に切り替えてみても、
結果は変わらなかった。

# 文字コード
ローカルでは、UTF-8。
WordPress も標準は UTF-8 のはず。

# WordPress固有の問題? テスト用のサーバでデバッグ
本番WordPressでは怖いので、以前作ったまま放置していた 別の WordPress でテスト。

こっちのサーバは、デバッグ用の設定になっている。

wp-config.php:84
define(‘WP_DEBUG’, true);

すると、3箇所に問題が起きていた。

Notice: Undefined index: text in /home/somof/somof.net/public_html/hawaii/wp-content/plugins/org2html/orgParser.php on line 189
Notice: Undefined index: args in /home/somof/somof.net/public_html/hawaii/wp-content/plugins/org2html/orgParser.php on line 387
Deprecated: Function split() is deprecated in /home/somof/somof.net/public_html/hawaii/wp-content/plugins/org2html/orgParser.php on line 96

暗黙の配列を、暗黙のNULLと仮定していたのを怒られているのと、
splitは廃止せい、という事らしい。

未定義のチェックを追加して、split() を、explode() に交換すると、
警告は無くなった。

# WordPress固有の問題? テスト用のサーバでデバッグ
ローカルに本番環境が無いので、サーバでログを吐かせてみると、

if (“” === $line) {

の行が動いていない事が分かった。
なんてことはない、WordPressの中の改行コードに ‘\r’ が混じっていたので、
‘\r’ を削除するコードを追加して、動作するようになった。

そのうち、サーバ側のPHPを 5.3 に戻しておこう。

# このプラグインを正しく成長させるにはWordPressの探求が必要そう
このプラグインは、要はテキストにHTMLタグを追加するフィルタなのだけど、
WordPress自身もHTMLタグを追加してくるので、
細かいことまで調整しようとすると、厄介。

せっかく、<PRE><CODE>で囲んでも、WordPressが改行に<BR>を追加してくる。

なので、間延びした表示になってしまった。

今回は、プラグイン側で泥縄的に最低限の見栄えまで帳尻を合わせたけども、
本当はちゃんとしないといけないんだろう。

CSSで調整しようにも、余計なタグを挿入されてしまうので、うまくいかない。

WordPress自体には、それ程興味もないしなぁ。

gitの設定とBitbucketのリポジトリ作りなおし

うっかり、gitのユーザ設定を忘れていたせいで、
Bitbucketに個人名で push していた。

Macのどこから個人名を見付けたのか分からないけど、
ちゃんと gitの user.name を指定すれば問題は解決。

$ git config –global user.name “somof”
$ git config –global user.email “somof@XXXX.ne.jp”

きれいさっぱり、リポジトリを削除して作り直し。

# Bitbucketのリポジトリを削除
左の「設定」から、「リポジトリを削除」を選択する。

# もう一回、Bitbucketにリポジトリを作成する
Bitbucketの「概要」から「リポジトリ作成」を選択。

出来たリポジトリは [org2html](https://bitbucket.org/somof/org2html.git)

今作ったリポジトリのページで、
Setting > デプロイ鍵 > 鍵を追加 から、公開鍵をコピペしておく。

# ローカルのgitリポジトリを削除して、作り直し
綺麗にフォルダごと作り直した後、新たに。

$ git init
$ git remote add origin https://somof@bitbucket.org/somof/org2html.git

何かコミットしておく。(でないとpushできないので)

$ git push –set-upstream origin master

あぶないあぶない。

PHPの勉強。あんがい面白い言語なんだな

WordPressのプラグインを作るために勉強したPHPの特徴のまとめ。

# 演算子の注意点
暗黙キャストの結果、予想外の結果になる場合があるので、要注意。

数字として不都合なく使えている様で、実際は文字列の事がある。
数字として比較したい場合は、明示的に数字にキャストするか、
厳密な比較(===)を使う。

また、演算子は左結合で少し変っているので、括弧を使って演算順を明示した方が良い。

# 配列
添字配列と連想配列が同じ、混在も可能。

キーが浮動小数点や論理型の場合、整数に丸められる。
更に、添字(風に書いた)配列は、実際には数字をキーにした
連想配列と同等なので、うっかり連想記憶の書式で重複させないこと。
重複した場合は、後の定義が有効になる。

キーが定義されているかどうかは array_key_exists($key, $array) が使えるが、
isset($array[‘key’]) の方が、たいていの場合高速に動作する。

# ブロック構文
中括弧{}だけでなく、 if/endif、switch/endswitch、while/endwhile、
for/endfor、foreach/endforeach が使える、

HTMLに混在して書く時に便利。

# 文字列からの関数呼び出し

call_user_func(‘funcname’, arg1, arg2…)
call_user_func_array(‘funcname’, array())

# lambda関数
create_function()関数があるのだけれど、見難いので、
function() {} 構文の方が良い。

# オブジェクトの複製ができる
python同様、複製しない代入は基本的に参照扱いになる。
複製が必要な場合は、以下のようにする。

$obj2 = clone $obj1;

# マルチバイト対応の文字列処理

–enable-mbstring で mbstring 関数を有効にする。
別途libmbflライブラリが必要。

大抵の場合は、標準の ereg_~関数で間に合いそうだけど。
必要に応じて。

|—————————————————————-+——————————————|
| 関数 | 用途 |
|—————————————————————-+——————————————|
| int mb_ereg(string $pattern , string $string [, array $regs ]) | マルチバイト文字列に正規表現マッチを行う |
| | |
|—————————————————————-+——————————————|

# 便利関数や定数など
|——————————————–+——————————–|
| 関数 | 用途 |
|——————————————–+——————————–|
| var_dump() | 変数の出力 |
| array_output($array) | 配列を一行ごと出力する |
| | |
| get_defined_constants() | 定義済み定数一覧 |
| get_defined_functions() | 定義済み関数一覧 |
| | |
| function_exists($name) | 関数の存在確認 |
| array_key_exists(l$key, $array) | 配列内のキーの存在確認 |
| | |
| split(‘,’,$str) | おなじみの文字列分解 |
| constants($name) | 名前の文字列から定数を取り出す |
| | |
| $funcname(); | 文字列 $funcname の名前の関数 |
| $$varname | 文字列 $varname の名前の変数 |
| | |
| isset($var) | 変数が定義されているかどうか |
| isarray($var) | 配列かどうか |
| | |
| intval($val), floatval($val), strval($val) | キャストする |
| | |
| get_resource_type($res) | |
| array_map(‘funcname’, $array) | |
| this/self/parent/static | |
|——————————————–+——————————–|

|—————+————————————|
| マジック定数 | 用途 |
|—————+————————————|
| __LINE__ | ファイル上の現在の行番号 |
| __FILE__ | ファイルのフルパスとファイル名 |
| __DIR__ | そのファイルの存在するディレクトリ |
| __FUNCTION__ | 関数名 |
| __CLASS__ | 名前空間も含んだクラス名 |
| __TRAIT__ | トレイト名 |
| __METHOD__ | クラスのメソッド名 |
| __NAMESPACE__ | 現在の名前空間 |
|—————+————————————|

# その他のTIPS
## エラー抑制演算子

$var = @$_GET[”];

など書くと、_GETにエラーがあっても、エラーが抑制される。

## 定数の定義
二通りの方法がある。

define(‘ORG_TYPE_TEXT’, 1);
const ORG_TYPE_TEXT = 1;

定数の場合、先頭の$は必要ない。
また、文字列から定数を取り出すには、constants()関数を使う。

$name = ‘ORG_TYPE_TEXT’;
echo constants($name), PHP_EOL;

constは、名前空間に影響を受ける。

## 配列の初期化
空ブラケットで追加しながら初期化することも出来る。

$vararray[] = ‘ar1’;
$vararray[] = ‘ar2’;
$vararray[] = ‘ar3’;
$vararray[] = ‘ar4’;

## 三項演算子

条件式 ? 式1 : 式2

条件式 ?: 式1

とも書ける。
この場合、条件式が真のときには条件式の値を、偽の場合は式1を返す

PHP で使う日本語正規表現のあれこれ

WordPressのプラグインを作るのに、日本語の正規表現が必要なのだけれど、
ぐぐると、何やら情報が混乱ぎみだったので、調べた結果だけをまとめておく。

まぁ、 WordPressのコーディングルールを見て、正式に公開する気は無くなったので、
自分(と自身で何とか出来る人)だけ使えれば良いのだけど。

orgのテーブルだけ変換するプラグインを作った時には何も考えなかったけれど、
Unicodeに対応するのは結構面倒だ、という話。

出来れば関わりたくない。
調べた結果、org-modeのタグを見付けるだけなら、意識しなくて良さそうだ。

# 正規表現の種類
まず、正規表現自体が3種類もある。(汗)

|———+———–+——————————-|
| 名称 | 種類 | 備考 |
|———+———–+——————————-|
| pcre | Perl 互換 | preg_~関数 |
| | | UTF-8 のみ扱える |
| | | パターン修飾子に u を指定する |
| | | 注意点がそれありに有る |
|———+———–+——————————-|
| mbregex | mbstring | mb_ereg~関数 |
| | | 別途インストールが必要 |
|———+———–+——————————-|
| regex | POSIX | 非推奨 |
|———+———–+——————————-|

余計なインストールを避けるなら、 pcre 一択。

とりあえず見付けた、pcre(Perl互換正規表現)の問題一覧。

– 対応する日本語コードは UTF-8 のみ
– UTF-8 を使う場合は、パターン修飾子に u を指定する(PCREのドキュメントに見付からないけど)
– 処理の制限値があり、越えると 0(マッチしない)を返す
– 文字クラス(alnum,alpha,ascii…)の動作が曖昧?ドキュメント上は日本語にマッチしないはずだけど。。。
– 「.」はデフォルトでは改行にマッチしない

# 使用する関数やライブラリ;mb_~は必要か?
mbstring を使う場合のデメリットはこんな感じ。

– WordPressのプラグインのために追加インストールが必要
– 内部エンコーディングとは別に、検索対象の日本語コードを指定する必要がある

追加しなきゃならないのは、今回は致命的だなぁ。

問題あるにせよ、気をつければ pcre(preg_match/preg_replace)で十分事足りそう。
日本語自体で正規表現を書かなければ良いのだし。

# Unicodeの制御信号、異体字セレクタなどの影響
日本人としては信じ難いことに、Unicodeには似た漢字を同じコードで表わす仕様がある。
Standardized VariantsとかVariation selectorとか、見たところ場当たり的に追加された様だ。

実際には、見付けたいのはアスキー文字の部分なので、
例えば「.*」に漢字を含めてくれるのなら、今回は気にしなくて良い。

問題の頻度を想像するに、起きてから対策すれば良い程度のものだろう。
そして今回は、起こりそうにない。(起さない… きっと)

wordpress PHP 正しいプラグインを作る作法;コードスタイル編

乱立していたスタイルを整理してくれたという方々に敬意を表して、
コードスタイルなどは、基本的には PSR に従うことにする。

だけども。
WordPress に必要な固有のルールもあるので、まとめておく。

# まず、PSRからの抜粋。

## 名前空間とクラス名の記構造

\<ベンダー名>\(<名前空間>\)*<クラス名>

区切り文字にバックスラッシュを使って良いらしい。
アンスコ”_”に、意味はないとか。

#+BEGIN_SRC php
// PHP 5.3 以降:
namespace Somof\WPPlugin;

class Org2Html
{
const VERSION = ‘0.1’;
const DATE_APPROVED = ‘2015-08-22’;
}
#+END_SRC

## ソースファイルの分割
クラス、関数、定数などを宣言するためのファイルと、
副作用のある処理を行うためのファイルは、分けるべき。

出力の生成部分はもちろん、
初期化ファイル(ini設定)の変更も副作用と考える。

## 命名規則
– クラス名は、StudlyCaps(単語の先頭文字を大文字で表記する記法)記法
– クラス定数は全て大文字とし、区切り文字にはアンスコを用いる
– メソッド名はcamelCase記法

## アクセス修飾子
– アクセス修飾子を、全てのプロパティ、メソッドに定義する
– abstractとfinalはアクセス修飾子の前に定義する
– staticはアクセス修飾子の後に定義する
– public : クラス内、クラス外のどこからでもアクセス可能
– private : 同じクラス内からのみアクセス可能
– protected : 同じクラス、及び子クラスからアクセス可能
– final : 拡張による変更禁止 (クラスとメソッドのみ)

# WordPress に必要なルール

以下、 [[http://wpdocs.osdn.jp/WordPress_%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E5%9F%BA%E6%BA%96][WordPress コーディング基準]] からの抜粋。

## シングルクォートとダブルクォート
シングルクォートとダブルクォートを適切に使い分ける。

– 文字列で何も評価しない場合は、シングルクォートを使う。
– セキュリティ上、HTML出力ではダブルクォートを使うべき
– 文字列で HTML クォートをエスケープする必要はほとんどない
– 例外は JavaScript
– ダブルまたはシングルクォートのどちらかを強制されるときがある

## WordPress の Data Validation について

## インデントとブレース、スペースの使い方
スペースではなく、本物のタブを使う。
むむむ。 これは守らないかも。

## include_once 対 require_once
include_once と require_once を適切に使い分ける。

「これら2つの構文は、 エラーの扱い方を除けば全く同様に振舞います。
 エラーが発生するとどちらも Warning を出力しますが、
 require() を使用している場合は Fatal Error となります」

## 正規表現
Perl 互換の正規表現 (PCRE, preg_ 関数) を使うこと。
POSIX 互換関数よりも好ましい。

## PHP ショートタグは禁止
PHP のショートタグ (<? … ?> や <?=$var?>)は使わない。
常に、完全な PHP タグ (<?php … ?>) を使う。

## 変数、関数、ファイル名と演算子
変数名、関数名はアルファベット小文字を使い、
単語の区切りはアンダースコア (_) を使う。
キャメルケースのような形式) は不可です。

ファイル名は動作を説明できるアルファベット小文字の名前とし、
単語の区切りにはハイフン (-) を使う。

1回しか使わない変数を作ってはいけない。

比較演算の時には、定数を左に、変数を右側に置く。

関数の引数のフラグは、意味の分かる値にしてください。
true/falseではなく、呼び出す側が読める文字列で渡す。

# さて、どんなルールにするか。

違和感のあるのは以下のルール。

– インデントにスペース禁止
– ファイル名のハイフン
– 命名規則で camelCase禁止
– 一度しか使用しない一時変数の使用禁止

手元にある、人の書いたプラグインを見ると、
camelCase禁止以外は、あまり守られていないみたいだ。

WordPressで公開する訳でなし、PHPの勉強の意味で長い目で見れば、
PSRに従っておいた方が良さそう。

PHP 開発ツールでテスト: 簡単CI testrunner

# testrunnerを用意する

とりあえず、最小限のものだけ composer でインストール。

#+BEGIN_SRC
{
“require-dev”: {
“phpunit/phpunit”: “4.*”,
“piece/stagehand-testrunner”: “4.1.0”
}
}
#+END_SRC

プロジェクト個別にインストールしたくなかったので、
global に testrunner をインストールできないものか試行錯誤したけど、
結局断念して、プロジェクトのフォルダに composer.json を作った。

なので、ここでは testrunner に最小限必要な phpunit だけを指定している。

#+BEGIN_SRC
$
$ composer.phar update
$
#+END_SRC

# testrunnerの実行

インストールしたら、あとは testrunner の実行。

#+BEGIN_SRC
$
$ ./vendor/bin/testrunner compile -p ./vendor/autoload.php
$ ./vendor/bin/testrunner phpunit -p ./vendor/autoload.php -a tests
$
#+END_SRC

これで、ファイルを更新する毎に、勝手にテストを実行してくれる。
これは便利。

ソース側の更新も監視したければ、こんな感じ。

#+BEGIN_SRC
$
$ ./vendor/bin/testrunner phpunit -p ./vendor/autoload.php -a tests -w src
$
#+END_SRC

他には、こんなオプションがある。

#+BEGIN_SRC
$ ./vendor/bin/testrunner phpunit –help
Usage:
phpunit [options] [–] []…

Arguments:
test_directory_or_file The directory or file that contains tests to be run (default: The working directory at testrunner startup)

Options:
-p, –preload-script=PRELOAD-SCRIPT The PHP script to be loaded before running a command
-c, –config=CONFIG The YAML-based configuration file for Stagehand_TestRunner
-R, –recursive Recursively runs tests in the specified directories.
-a, –autotest Monitors for changes in the specified directories and run tests when changes are detected.
-w, –watch-dir=WATCH-DIR The directory to be monitored for changes (default: The directories specified by the arguments) (multiple values allowed)
-m, –notify Notifies test results by using the growlnotify command in Mac OS X and Windows or the notify-send command in Linux.
-d, –detailed-progress Prints detailed progress report.
-s, –stop-on-failure Stops the test run when the first failure or error is raised.
–log-junit=LOG-JUNIT Logs test results into the specified file in the JUnit XML format.
–log-junit-realtime Logs test results in real-time into the specified file in the JUnit XML format.
–test-file-pattern=TEST-FILE-PATTERN The regular expression pattern for test files (default: Test(?:Case)?\.php$)
–test-method=TEST-METHOD The test method to be run (multiple values allowed)
–test-class=TEST-CLASS The test class to be run (multiple values allowed)
–phpunit-config=PHPUNIT-CONFIG The PHPUnit XML configuration file
-h, –help Prints help and exit.
-V, –version Prints version information and exit.
–ansi Enables ANSI output.
–no-ansi Disables ANSI output.

Help:
The phpunit command runs tests with PHPUnit:

testrunner phpunit …
#+END_SRC

開発初期なんかは、Jenkinsにやらせるより数段小回りが効いて良いかも。

WordPressのプラグイン開発。PHPのツールとJenkinsプラグインの用意

PHP関係のパケージの管理は、 composer を使う。

# まずは、composer のダウンロード。

$
$ curl -sS https://getcomposer.org/installer | php
$

composer には、他に以下のようなコマンドもある。

$ composer.phar install # 先に composer.json にパッケジを書いておく
$ composer.phar update
$ composer.phar remove # composer.json を編集して update の方が分り易い

# PUPUnitのインストールのお試し
PHPは趣味にしか使わないから、インストール先は global にしておく。

$
$ composer.phar global require “phpunit/phpunit=4.0.*”
$

これで ~/.composer に phpunit がインストールされる。
(この後直ぐにアンインストールしたけど)

この段階で “phpunit/phpunit=4.8.*” だと、依存関係を解決できなくて
実際にはインストールできない。

# PHP ビルドツール Phing をインストールする

~/.composer/composer.json を編集して、
phing だけ追加して composer.phar update してみると、
いろいろお勧めされる。

phing/phing suggests installing phpdocumentor/phpdocumentor (Documentation Generator for PHP)
phing/phing suggests installing sebastian/phpcpd (Copy/Paste Detector (CPD) for PHP code)
phing/phing suggests installing phpmd/phpmd (PHP version of PMD tool)
phing/phing suggests installing pdepend/pdepend (PHP version of JDepend)
phing/phing suggests installing phploc/phploc (A tool for quickly measuring the size of a PHP project)
phing/phing suggests installing phpunit/phpunit (The PHP Unit Testing Framework)
phing/phing suggests installing phpunit/php-code-coverage (Library that provides collection, processing, and rendering functionality for PHP code coverage information)
phing/phing suggests installing pear/versioncontrol_svn (A simple OO-style interface for Subversion, the free/open-source version control system)
phing/phing suggests installing pear/versioncontrol_git (A library that provides OO interface to handle Git repository)
phing/phing suggests installing pear/archive_tar (Tar file management class)
phing/phing suggests installing tedivm/jshrink (Javascript Minifier built in PHP)

ドキュメントにはSphinxを使うので phpDocumentor はイイかな。。。
いらない物もあるし、以下の様にして、再度 update。

{
“require-dev”: {
“phing/phing”: “*”,
“phpunit/phpunit”: “4.*”,
“squizlabs/php_codesniffer”: “*”,
“phploc/phploc”: “*”,
“pdepend/pdepend” : “*”,
“phpmd/phpmd” : “*”,
“sebastian/phpcpd”: “*”,
“theseer/phpdox”: “*”
}
}

これで実際にインストールされたのは以下のパッケージ達。

|———————————–+———+—————————————————————-|
| packeage | version | desc. |
|———————————–+———+—————————————————————-|
| doctrine/instantiator | 1.0.5 | A small, lightweight utility to instantiate objects in PHP … |
| nikic/php-parser | v1.3.0 | A PHP parser written in PHP |
| pdepend/pdepend | 2.1.0 | Official version of pdepend to be handled with Composer |
| phing/phing | 2.11.0 | PHing Is Not GNU make; it’s a PHP project build system or b… |
| phpdocumentor/reflection-docblock | 2.0.4 | |
| phploc/phploc | 2.1.4 | A tool for quickly measuring the size of a PHP project. |
| phpmd/phpmd | 2.2.3 | PHPMD is a spin-off project of PHP Depend and aims to be a … |
| phpspec/prophecy | v1.5.0 | Highly opinionated mocking framework for PHP 5.3+ |
| phpunit/php-code-coverage | 2.2.2 | Library that provides collection, processing, and rendering… |
| phpunit/php-file-iterator | 1.4.1 | FilterIterator implementation that filters files based on a… |
| phpunit/php-text-template | 1.2.1 | Simple template engine. |
| phpunit/php-timer | 1.0.7 | Utility class for timing |
| phpunit/php-token-stream | 1.4.6 | Wrapper around PHP’s tokenizer extension. |
| phpunit/phpunit | 4.8.5 | The PHP Unit Testing framework. |
| phpunit/phpunit-mock-objects | 2.3.7 | Mock Object library for PHPUnit |
| sebastian/comparator | 1.2.0 | Provides the functionality to compare PHP values for equality |
| sebastian/diff | 1.3.0 | Diff implementation |
| sebastian/environment | 1.3.2 | Provides functionality to handle HHVM/PHP environments |
| sebastian/exporter | 1.2.1 | Provides the functionality to export PHP variables for visu… |
| sebastian/finder-facade | 1.2.0 | FinderFacade is a convenience wrapper for Symfony’s Finder … |
| sebastian/git | 2.0.1 | Simple wrapper for Git |
| sebastian/global-state | 1.0.0 | Snapshotting of global state |
| sebastian/phpcpd | 2.0.2 | Copy/Paste Detector (CPD) for PHP code. |
| sebastian/recursion-context | 1.0.1 | Provides functionality to recursively process PHP variables |
| sebastian/version | 1.0.6 | Library that helps with managing the version number of Git-… |
| squizlabs/php_codesniffer | 2.3.3 | PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and… |
| symfony/config | v2.7.3 | Symfony Config Component |
| symfony/console | v2.7.3 | Symfony Console Component |
| symfony/dependency-injection | v2.7.3 | Symfony DependencyInjection Component |
| symfony/filesystem | v2.7.3 | Symfony Filesystem Component |
| symfony/finder | v2.7.3 | Symfony Finder Component |
| symfony/yaml | v2.7.3 | Symfony Yaml Component |
| theseer/directoryscanner | 1.3.1 | A recursive directory scanner and filter |
| theseer/fdomdocument | 1.6.1 | The classes contained within this repository extend the sta… |
| theseer/fxsl | 1.1.1 | An XSL wrapper / extension to the PHP 5.x XSLTProcessor wit… |
| theseer/phpdox | 0.8.1.1 | A fast Documentation generator for PHP Code using standard … |
|———————————–+———+—————————————————————-|

# コード品質を高める、おなじみっぽい名前のツール達
CppUnitが会社の規定に合わないので、xUnit系のテストを触るのは始めてだ。
他に C++でもお世話になった記憶のあるPMDの親戚達もインストールされた。

– PHPUnit: xUnitの親戚。PHPテストコードを実行する
– phpcs (php_codesniffer): コーディング規約チェック
– phpmd: 怪しい実装方法の箇所をチェック
– phpcpd: コードの重複をチェック

# Jenkinsプラグインのインストール
Jenkins のプラグインには、 PHP Plugin と Phing Plugin をインストール。
これだけで依存するパッケージが細々とインストールされる。

あれ? DRY plugin が選べなくななってる。
最近の Jenkins に対応していないらしい。

自動的にインストールされた “Duplicate Code Scanner Plug-in” って言うのが
代わりに使えそうなので、このまま進めよう。

# カバレッジツールが入ってない
PHPUnitからxdebugを呼び出して計測するつもりなのだけど、
xdebugが composerでインストールできていない。

[xdebug](http://xdebug.org/docs/install) を読むと、
自分でビルドする必要がありそう。

brewでも入れられるけど、PHPはせっかくcomposerで管理しているので、
混乱が無いようにしておきたい。

まだ使わないので、おいおいインストールすることにしよう。

#+BEGIN_COMMENT
/etc/php.d/xdebug.ini に以下の設定を追加。
zend_extension=/usr/lib64/php/modules/xdebug.so

http://www.spiceworks.co.jp/blog/?p=4188

http://qiita.com/khironori/items/c145d7e3eed7b2a5a01a
#+END_COMMENT