月別アーカイブ: 2015年9月

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

ステンドグラスの設計図を作りたい。その前に

ステンドグラスの設計図を作る前に、ステンドグラスの頂点情報をPythonで作っておいた方が融通が効きそう。

綺麗に化粧直しして、ガラスっぽくレンダリングするのを Blenderでやってみたいと思う。

作った設計図の概要

  • 頂点と面情報をもった、ガラス板の集合
  • 高さと半径をパラメータにして、全体のサイズとアスペクト比を自動計算する
  • 円周方向の部品数をパラメータ化

今予め用意したのは、小物入れのポリゴンデータ

Blenderに期待している機能

  • pythonで別途自作した頂点情報と面情報の読み込み
  • 部品の嵌め合いと、半田(ステンドグラスの固定に使っている)の再現
  • 透明なガラス素材で、色の具合を確認したい
  • (今の図面は小物入れだけど)中に光源を入れて、ランプとしての出来上がりを見たい
  • 出来れば、まだらなガラスも試したい
  • 箱と蓋の嵌め合いを確認したい

まずはスケール合わせ

設計図の寸法はミリ単位で扱っているのだけれど、 Blenderの単位 BU(Blender Unit)とは標準的な数字の大きさが合わず、 そのままポリゴン表示すると画面に収まり切らない。

スケールを合わせる方法は、

  1. 単純にオブジェクトを縮小する
  2. 座標系をミリ単位にして、表示幅を設定する

1の方法は、 object.scale = (0.1, 0.1, 0.1) とすれば1/10になる。 こうしてBUに数字の大きさを合わせれば、表示のパラメータを調整する必要がない。 ただ、実際の寸法が変わってしまうと何かと不便。

2の方法をGUIで設定するには、 右側の「Scene」ウインドウの「Scene」タブの「単位」でメートル法を選んで、 拡大縮小を””1.0″”から””0.001″”にする。これでmm単位になる。

これをスクリプトで設定する方法は以下の通り。

bpy.context.scene.unit_settings.system='METRIC'
bpy.context.scene.unit_settings.scale_length = 0.001

これだけだと画面からはみ出してしまうので、 視点位置なども調整する必要がある。

3DViewのグリッドの調整

スケールをミリ単位にすると、グリッドが大き過ぎて目安にならない。 グリッドの方は、1cm単位にしよう。

for a in bpy.context.screen.areas:
    if a.type == 'VIEW_3D':
        bpy.types.SpaceView3D(a.spaces[0]).grid_lines = 30
        bpy.types.SpaceView3D(a.spaces[0]).grid_scale = 0.01

カメラと照明の位置が近すぎる

カメラと照明が、部品の内側に入ってしまったので、 位置を少し遠めに変更する。

こんな感じ。ついでに背景にも色をつけておくと見易い。

# Lamp
lamp = bpy.data.objects['Lamp']
lamp.location = (250, 250, 100)
lamp.rotation_euler = (0, 0, 0)
lamp.data.falloff_type = 'INVERSE_LINEAR'
lamp.data.shadow_method = 'NOSHADOW'

# Camera
camera = bpy.data.objects['Camera']
camera.location = (200, 0, 100)  # 100 = 10cm
camera.rotation_euler = (1.221, 0, 1.57)  # 70, 0, 90
camera.data.type = 'PERSP'
camera.data.angle = 0.7
camera.data.clip_start = 0
camera.data.clip_end = 1000

# Background
world = bpy.data.worlds['World']
world.horizon_color = (0.8, 0.8, 0.8)
world.zenith_color = (0.1, 0.1, 0.1)
world.use_sky_blend = True

全体がレンダリングされない

ミリスケールにすると、大きめの部品を作った場合にレンダリングされない部分が出てくる。

レンダリングする範囲をクリップしている設定を合わせてあげると良い。

# Camera
camera.data.clip_start = 0
camera.data.clip_end = 1000

作業中の 3DViewの視点が近すぎる (未解決)

GUIではマウスで簡単に操作出来るのだけれど、 スクリプトで変更する方法が見付からない。

スクリプトでレンダリングした結果を見る分には困らないので、 おいおい考えることにする。

とりあえず以下の様にすれば、オブジェクトが全部見える位置に移動できる。

# 3D View の視点操作
for area in bpy.context.screen.areas:
    if area.type == 'VIEW_3D':
        for region in area.regions:
            if region.type == 'WINDOW':
                override = {'area': area, 'region': region, 'edit_object': bpy.context.edit_object}
                bpy.ops.view3d.view_all(override)

あと、毎回出てくる画面、スプラッシュウィンドウを消す

毎回起動直後に出てくるBlenderの紹介?画面。 スクリプトで動かしている時には、邪魔でしかない。

あのウインドウの名前が分からなかったので、消すのに時間がかかった。(汗)

ファイル>ユーザー設定>インターフェース タブ の右下にある 「スプラッシュを表示」のチェックを外すと、今後表示されない。

これで幾分快適になった。

これまでの設定の後、さくっとレンダリングした結果はこんな感じ。

image.png

matplotlibで表示したのと、微妙に位置がずれていたり。 あんまりステンドグラスっぽく見えないのを、この後直していきたい。

ステンドグラスの設計には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で作り直してみよう。

BootCampのWindows8.1とUSキーボードでGoogle日本語変換を使う

滅多に使わないのだけど。
念のためにMacBookAirにはBootCamp上に
Windows8.1とMSOfficeをインストールしてある。
脊髄反射的に、Google日本語変換も。

この環境だと日本語キーボードが前提になるらしく、
キーボードショートカットで日本語変換できない。

変換キーとか英数キーとか無いからね。

で、USキーボードでも使えるように
Google日本語変換のプロパティから、
IMEを有効・無効にするキーを追加してあげる。

この時、
何となく指に覚えがある「Shift Space」では上手く動作しない。
IMEをONにはできるけれど、OFFにできない。

「Control Space」ならOKなので、以下の3つを追加する。

|————–+————+————-|
| モード | 入力キー | コマンド |
|————–+————+————-|
| 直接入力 | Ctrl Space | IMEを有効化 |
| 直接入力 | Ctrl Space | IMEを無効化 |
| 入力文字なし | Ctrl Space | IMEを無効化 |
|————–+————+————-|

つまらない事で、小一時間悩んでしまった。

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にやらせるより数段小回りが効いて良いかも。