ごらくらいふ

プログラミングしたりゲームしたり

Rust Vec<T>を特定の長さで分割する

背景

gifとかzipとかパースしたいなあ+Rust触りたいなあ! ということで、まずはバイナリダンプから始めようとした。

以下のようなフォーマットで標準出力に吐き出したい。

50 4b 03 04 00 00 00 00 00 00 00 00 00 00 00 00 | PK.............. 

一行出力するにあたり、バイナリのほか、一時的に格納した文字列情報が必要。

最初はfor文に食わせて、愚直にカウンタ制御でVecに文字を詰めたり改行して実装した。 当然ながら、どこまで出力されているかを意識してコードを書かなければならない。

これではしんどいので、octet単位ではなく行単位の出力で考えたい。

目的

Vec<u8> *1 を二次元配列的に扱えるように変換する。

結論

let lines: Vec<&[u8]> = binary.chunks(BYTES_IN_LINE).collect();

各行の長さをあとで変えたり、所有権も持たせたくてVec<Vec<u8>>が良いならば以下のとおり。

const BYTES_IN_LINE: usize = 16;
let lines: Vec<Vec<u8>> = binary.chunks(BYTES_IN_LINE).map(|chunk| chunk.to_vec()).collect();

余談

.chunksを探しに行く前に、愚直に作る処理を書いてみたのだけれど、これが数行で済むのだから便利だなぁ。

const BYTES_IN_LINE: usize = 16;
let lines: &mut Vec<Vec<u8>> = &mut vec![];
let mut line: Vec<u8> = vec![];
for octet in binary {
    line.push(octet.clone());
    if line.len() >= BYTES_IN_LINE {
        lines.push(line);
        line = vec![];
    }
}
if line.len() > 0 {
    lines.push(line);
}

*1:軽量なデータから始めるので、fs.read(path) -> Vecを使う。

DeployGateのコマンドラインツールから Commands::Deploy Error: NoMethodError と怒られる件

環境

  • ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]
  • deploygate-cli v0.6.4
  • Xcode 9.4.1

現象

dg deployを実行すると、適切にBundle Identifierを指定しているにも関わらず、Bundle Identifierの入力を求められたのち、 下記のエラーが発生する。

Status
deploygate-cli ver 0.6.4

Error message
undefined method `build_configuration_list' for nil:NilClass

Backtrace
/path/to/gemroot/gems/deploygate-0.6.4/lib/deploygate/xcode/analyze.rb:145:in `target_build_configration'
/path/to/gemroot/gems/deploygate-0.6.4/lib/deploygate/xcode/analyze.rb:91:in `target_xcode_setting_provisioning_profile_uuid'
/path/to/gemroot/gems/deploygate-0.6.4/lib/deploygate/commands/deploy/build.rb:50:in `ios'
/path/to/gemroot/gems/deploygate-0.6.4/lib/deploygate/commands/deploy/build.rb:22:in `run'
/path/to/gemroot/gems/deploygate-0.6.4/lib/deploygate/commands/deploy.rb:16:in `run'
/path/to/gemroot/gems/deploygate-0.6.4/lib/deploygate/command_builder.rb:70:in `block (2 levels) in run'
/path/to/gemroot/gems/commander-4.4.5/lib/commander/command.rb:182:in `call'
/path/to/gemroot/gems/commander-4.4.5/lib/commander/command.rb:153:in `run'
/path/to/gemroot/gems/commander-4.4.5/lib/commander/runner.rb:446:in `run_active_command'
/path/to/gemroot/gems/fastlane-2.57.2/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb:64:in `run!'
/path/to/gemroot/gems/commander-4.4.5/lib/commander/delegates.rb:15:in `run!'
/path/to/gemroot/gems/deploygate-0.6.4/lib/deploygate/command_builder.rb:128:in `run'
/path/to/gemroot/gems/deploygate-0.6.4/bin/dg:6:in `<top (required)>'
/path/to/gemroot/bin/dg:23:in `load'
/path/to/gemroot/bin/dg:23:in `<main>'
/path/to/gemroot/bin/ruby_executable_hooks:15:in `eval'
/path/to/gemroot/bin/ruby_executable_hooks:15:in `<main>'

解消方法

Xcodeのメニューバーから、[Product]> [Scheme]> [Manage Schemes ...] を開き、閉じる。

原因

  • lib/deploygate/xcode/analyze.rbが必要とする、*.xcschemeが存在しないため

調査記録

なんだか業務issue感さえ漂うので、何を調べたのか書き残す。余談。

Backtraceいわく、target_build_configrationの処理中に問題が発生したことがわかる。

def target_build_configration
  target_project_setting.build_configuration_list.build_configurations.reject{|conf| conf.name != @build_configuration}.first
end

https://github.com/DeployGate/deploygate-cli/blob/v0.6.4/lib/deploygate/xcode/analyze.rb#L145

undefined method 'build_configuration_list' for nil:NilClassということから、target_project_settingの結果がnilであることが直接の問題であるとわかる。

def target_project_setting
  scheme_file = find_xcschemes
  xs = Xcodeproj::XCScheme.new(scheme_file)
  target_name = xs.profile_action.buildable_product_runnable.buildable_reference.target_name


  target_project.native_targets.reject{|target| target.name != target_name}.first
end

https://github.com/DeployGate/deploygate-cli/blob/v0.6.4/lib/deploygate/xcode/analyze.rb#L153-L155

ではtarget_project_settingの中身で何が起きているのか確認するため、scheme_file, xs, target_nameをprintしてみたところ、すべてnilであることが確認できた。

この時点で、まずfind_xcschemesが怪しいと直感を得た。(悪い癖)

native_targets.reject{|target| target.name != target_name}を見て、「ああ、target_nameがnilになっちゃって正しいtargetも捨てちゃってるんだな」という認識を挟むのが正しい怪しみ方だろう。

def find_xcschemes
  shared_schemes = Dir[File.join(@xcodeproj, 'xcshareddata', 'xcschemes', '*.xcscheme')].reject do |scheme|
    @scheme != File.basename(scheme, '.xcscheme')
  end
  user_schemes = Dir[File.join(@xcodeproj, 'xcuserdata', '*.xcuserdatad', 'xcschemes', '*.xcscheme')].reject do |scheme|
    @scheme != File.basename(scheme, '.xcscheme')
  end


  shared_schemes.concat(user_schemes).first
end

https://github.com/DeployGate/deploygate-cli/blob/v0.6.4/lib/deploygate/xcode/analyze.rb#L165-L170

で、find_xcschemesの中にあるshared_schemes, user_schemesもprintしてみればこっちもnilだと確認した。 というかブロックの中に入っていなかった。

File.joinで組んでいるパターンをターミナルからも確かめた結果、*.xcschemeが生成されていないことがわかった。 おそらくこれが原因だろうと、schemeを作る手段を求めて上記解消方法を試したところ、*.xcschemeが生成されたことを確認できた。

UITextFieldの内容をUserDefaultsに自動保存する。(+ 保存用のキーをInterfaceBuilderで設定する)

寄り道を経てカスタムクラスの最適解に降り立った気がする。

This UITextField is save to UserDefaults when edit ...

編集終了のタイミングでUserDefaultsに書き込んでくれる。

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var textField: RestorableTextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.textField.restoreByUserDefaults()
    }
}

Interface-Builderで紐づけたら、あとは呼び出すだけ。

リファクタリング「リトル・レディ」 #1 画像ボタンをホバーで差し替える処理

約3年も前の話、「リトル・レディ」という作品をChromeで動くようにしたい! という思いのもと、勝手に復活開発日誌を始めた。

yajamon.hatenablog.com

yajamon.hatenablog.com

この開発は一気に進み、2年弱放置の後に完結宣言が行われた。

この記事は?

この記事はいわば番外編。今風のコードに書き換えていく活動の上で何をしたか記録していく。

目下目的はHTML5に馴染む形に書き換えること。野心はSingle Page Applicationにすること。 自分でアプリケーションを設計して、脚本を読み込むようにする。 そして、リトル・レディの脚本を抽出・変換ツールを用意することで、自分以外の人に体験してもらえる状況に持ち込むのが到達点。

画像の差し替え処理を書き換える

スタート画面では、<a>タグをボタンに見立て、中に画像を配置している。

/index.htm

<script language="JavaScript">
// プリロード
if(document.images) {
    var imgPreload1 = new Image() ; imgPreload1.src = "image/basis/menu1-2.png";
    // ...つづく
}
</script>
<a href="javascript:topS()" onMouseOver="menu1.src='image/basis/menu1-2.png'" onMouseOut="menu1.src='image/basis/menu1-1.png'"><img SRC="image/basis/menu1-1.png" border=0 name="menu1"></a>
<!-- つづく -->

<img>name属性で識別され、ボタンへのマウスオーバー(アウト)、で差し替えている。 スムーズに差し替えられるよう、ホバー用の画像はコード上で食わせて、プリロードとしている。

body以下のツリーに足したりしていないので、現代のブラウザでプリロードが行われるのか不安だったが、問題なくプリロードされているようだった。

修正後

<style>
    .btn-base, .btn-hover {
        border : 0;
    }
    .btn .btn-base {
        display: inline-block;
    }
    .btn:hover .btn-base {
        display: none;
    }
    .btn .btn-hover {
        display: none;
    }
    .btn:hover .btn-hover {
        display: inline-block;
    }
</style>
<a href="javascript:topS()" class="btn" ><img class="btn-base" src="image/basis/menu1-1.png"><img class="btn-hover" src="image/basis/menu1-2.png"></a>
<!-- つづく -->

<a>の中に通常時、ホバー時の画像を指定してしまい、CSS:hover疑似クラスとdisplay:要素で表示制御するようにした。

行数は多少増えてしまった感があるが、HTMLにハードコードされたonMouseOver, onMouseOutを排除することができた。 また、ボタンの数に対する編集箇所が一箇所に集まったのでこの方法が好きかな。(今後増えたりする見込みはないけれど…)

ほかにもCSSでボタンごとにa.btn-start:hover { background-image: url(...) }とかも考えたけれど、気にするところが増えたのでやめた。*1, *2

余談

完結宣言から1年経って手を付け始めたのだけれど、タイトルが予言されてて笑ってしまった。

これから手を加えるのは、より現代ブラウザ向けの修正になるので、"リファクタリング:リトル・レディ"とかのタイトルでやろうかな。

yajamon.hatenablog.com

*1:ボタンの数だけスタイルとHTMLに対処を書き込む必要があったり

*2:widthどうするん…画像サイズに合わせなきゃ…など

Chromeの開発者ツールで選択した要素のHTMLElementを教えてくれるやつ、Ctrl+Shift+C がショートカットキーだった。

Chrome 67 で確認。 MacだとCmd+Shift+Cね。

URLとタイトルをひとまとめにクリップボードへ突っ込んでくれるChrome拡張がお亡くなりになったみたいで、 自作するしかないかー、そういえば空いてるショートカットキーはあるかななどと触ってたら動いて驚いた。

ぱぱっとかき捨てたいけどsyntax highlightとかエディタのサポートほしい…

/tmpに書けばよかったんや

vim /tmp/draft.md

Zaif Apiを叩くツール zacli v0.1.0 をリリースした。

Rust製のZaif API Wrapperを作っているので、これをコマンドラインツールとして使用するCrateを作成した。

yajamon.hatenablog.com

インストール方法

RustとCargoの準備が整っているなら、以下のコマンドでインストールできる。

cargo install zacli

使い方

通貨ペアを確認したり

$ zacli currency_pairs all | grep zaif
currency_pair: zaif_jpy
currency_pair: zaif_btc

板情報を確認したり

$ zacli depth zaif_jpy
type    price   amount
ask     1.01    15000.0
ask     1.02    500.2
...
bid     1.005    12000.0
bid     1.0048   450.5

注文できます。

$ zacli trade zaif_jpy bid 1.0 100

Crateとか

https://crates.io/crates/zacli

要望とかあったらissue, P-r待ってます。

https://github.com/yajamon/zacli/issues