CORDEA blog

Android applications engineer

Chrome のコンテキストメニューから印刷...を消す

定期的に検索と印刷...を押し間違えて辛いので消したメモ。
もしかしたら Chrome の設定とかでできるかもしれないので、直接書き換えたくない人は探してみてください。

やり方については StackExchange に載っている通りで、Preferences の printing.enabled を false にすれば良いという話。

superuser.com

この Preferences は macOS の場合 ~/Library/Application Support/Google/Chrome/Default 配下にあります。 (Windows の場合の PATH は先のリンクに書いてありました)
printer とかがある人はすでに "printing" があると思うので、そこに "enabled" を書き加えると良いです。

Before

f:id:CORDEA:20190414121735p:plain

After

f:id:CORDEA:20190414121757p:plain

backup を用意した後 jq で format して書き換えて入れておいたのですが、起動時に勝手に minify してくれました。

おわり

Thread を toString した時の Thread[foo,0,bar]

RxJava とか使ってると稀によく見る Thread[main,5,main] みたいなやつ、どれがどれだっけってなったのでメモ

そもそも RxJava の source から読み始めたのでアレなんですが、
タイトルに書いてあるように Thread の doc か toString の実装を見ればいいです
Thread (Java Platform SE 8)
jdk8/jdk8/jdk: 687fd7c7986d src/share/classes/java/lang/Thread.java

"Thread[" + スレッド名 + "," + 優先順位 + "," + スレッドグループ + "]"

RxJava でよく見る RxCachedThreadScheduler-0 はここです

RxJava/IoScheduler.java at v2.2.8 · ReactiveX/RxJava · GitHub

後ろの番号を set しているのは

RxJava/RxThreadFactory.java at v2.2.8 · ReactiveX/RxJava · GitHub

おわり

static method 等を呼び出しているテストケースで Robolectric の Shadow を使う

あんまり知られてないような知られてるような、そんな感じがしたので Robolectric の Shadow の使い道をちょっと紹介します。

robolectric.org

紹介するのは

  • static method を呼び出ている
  • kotlin の object 宣言がされた singleton を内部で直接使用している
  • 内部で new している

などなど、色々な記事で PowerMock の出番とされていそうなケースについてです。

今回はこれを Robolectric の Shadow で解決します。
前提として、私は PowerMock を入れようと思った時、それは設計を見直しをするべき時だと考えています。
とはいえ、古いアプリや大規模なアプリなどでテストは書きたいが static method の呼び出しがネックになっている、直す工数もない。しかし PowerMock は入れたくないというケースは稀ですが存在します。
そんな時、使うべきかは置いておいて Shadow が使えます。

いくつか例を紹介します。
この例は全て GitHub にあります (難読化された感じの雑な命名はあとで直します)
github.com

1 つ目

object AUtil {
    fun a() {
        throw IllegalArgumentException()
    }

    @JvmStatic
    fun b() {
        throw IllegalArgumentException()
    }
}

class A {
    fun a() {
        AUtil.a()
    }

    fun b() {
        AUtil.b()
    }
}

1 つ目の例はこれです。
こんなの存在しないと思いますが、テストからアクセスできない何かにアクセスして throw されてる、でもその後の処理がテストしたい...!みたいな、そんな感じで考えてください。

これに対しては、以下のように Shadow を定義できます。

@Implements(AUtil::class)
class ShadowAUtil {
    companion object {
        @JvmStatic
        @Implementation
        fun b() {
        }
    }

    @Implementation
    fun a() {
    }
}

これを使用するとテストを通過させることができます。

@RunWith(AndroidJUnit4::class)
@Config(shadows = [ATest.ShadowAUtil::class])
class ATest {
    @Test
    fun a() {
        A().a()
    }

    @Test
    fun b() {
        A().b()
    }

    ...
}

2 つ目

2 つ目は内部で new していて、なんか失敗しているケースです。
Shadow は constructor の呼び出しにも対応しています。

class D(d: String) {
    init {
        throw IllegalArgumentException()
    }
}

以下のような Shadow を定義します

@Implements(D::class)
class ShadowD {
    @Implementation
    fun __constructor__(d: String) {
    }
}

これを使用すると通過します
また、これは変な使い方として、

class B(private val b: String)

このようなクラスを Java 側から使用するとして

public class C {
    public void c() {
        new B(null);
    }
}

null を入れてしまうと当たり前ですが java.lang.IllegalArgumentException: Parameter specified as non-null is null ... が発生します
が、以下のような Shadow を定義すると回避できます。

@Implements(B::class)
class ShadowB {
    @Implementation
    fun __constructor__(b: String?) {
    }
}

使い所はありません。

3 つ目

実際に呼び出されたかどうか知りたい時、引数を assert したいときなど。ここまで来たら PowerMock 使えばという話なんですが、可能です。

@Implements(AUtil::class)
class ShadowAUtil {
    var isPassed = false

    @Implementation
    fun a() {
        isPassed = true
    }
}

とりあえずこんな感じで定義しました。
Robolectric は object に対応する Shadow を受け取ることができます。

@Test
@Config(shadows = [ShadowAUtil::class])
fun a() {
    val util = Shadow.extract<ShadowAUtil>(AUtil)
    assert(!util.isPassed)
    A().a()
    assert(util.isPassed)
}

便利です。

Shadow は多くの場面で活躍しますが、一方で何をしているのかが慣れるまで分かりづらいという欠点がありますので、用法用量を守って使用すると良さそうです。

Mackerel Client 1.2 をリリースしました

この度、MackerelClient 1.2 をリリースしましたので、リリースノートに書かなかった諸々を書きます。
ちなみに 1.1 (2016年4月24日) 以来、2 年半ぶりの更新となります。

Get it on Google Play

反映されるのはもう少し後かもしれません
スクリーンショット等はそのうち更新します

github.com

リリース内容

  • アラート一覧にホスト名や監視設定の値を表示するようにした
  • アラートの取得、グラフの描画を早くした
  • デザイン修正
    • card 部分のスタイルをちょっと変えた
    • グラフ部分のスタイルをちょっと変えた
  • バグ修正
    • ドロワーの文字色がいつの間にか毒々しくなってたので直した (というか直った)
  • min sdk version: 19 -> 21
  • target sdk version 23 -> 28

内部的な変更

  • 264 files changed, 8403 insertions(+), 6158 deletions(-)
  • ktlint の導入
  • dagger の導入
  • databinding の導入
  • groupie の導入
  • parcelize の導入
  • AndroidX 対応
  • 諸々のバージョンアップ
    • kotlin 1.0.1 -> 1.2.71
    • realm 0.87.2 -> 5.1.0

大規模な設計の見直しが入っており、差分がかなり大きくなりました。
グラフの描画部分など、主機能については大きく書き直しています。
まだ完全ではありませんが、まぁまぁまともになってきています。


気が向いたら使ってみてください。

Hy と Python の version について

Hy の install 時に Python version で少し困ったりしたのでメモ

普通に Python 3.7.0 の環境で Hy を pip install して実行すると

ImportError: invalid flags 1531398560 in 'hy.core.language'

こうなったり、または一回は実行できるけど二度目は失敗する、みたいなことになる

Hy 0.14.0 は Python 3.7.0 に対応していないためにこのエラーは起きているようで
これより後に 3.7.0 対応が行われている

と言うわけで対応としては公式通り、基本的には

$ pip install hy

よりも

$ pip install git+https://github.com/hylang/hy.git

の方が良さげ

Spacemacs の install で嵌ったりした

最近 Lisp 方言を書く機会が多いので重い腰を上げて Emacs を入れました
といっても素の Emacs を育てるには Vim に染まりすぎたので
Spacemacs という Emacs の distribution に頼ることにしました

嵌ったところ

公式にしたがって ~/.emacs.d に clone したのですが

Error (use-package): org-projectile :config: Symbol's function definition is void "projectile-global-mode"

的なことを言われたり言われなかったり、mode がうまく切り替わらなかったりして嵌ってました

で、spacemacs 自体を develop に切り替えることでうまくいきました
予想ですが、この PR が関係してそうだなと

$ cd ~/.emacs.d
$ git checkout develop

このあと一応 dotspacemacs/install し直してます

その他

思ったより Spacemacs 良かったです
C-x C-c と C-g だけ覚えとけばなんとかなる

Docker で mediawiki 立てて oauth extension 入れるまで

前も似たようなこと書いた気がするけど...
検証用に local で一時的に立ててるものなので色々ご注意ください。

build

docker hub から引っ張ってくると mediawiki が古い (多分) ので公式 repository を clone して build します

$ git clone https://github.com/wikimedia/mediawiki-docker.git
$ docker build --rm -t mediawiki:latest mediawiki-docker/stable/

run

立てます、動けばいいので色々適当です

$ docker run -it -d -e MYSQL_ROOT_PASSWORD="root" --name mysql mysql
$ docker run -it -d -e MEDIAWIKI_DB_PASSWORD="root" -e MEDIAWIKI_DB_TYPE="mysql" -p 8080:80 --link mysql:mysql --name mediawiki mediawiki:latest

ここからは http://localhost:8080 にアクセスしつつ色々進めます。
途中に入れる db への接続先は

$ docker inspect -f '{{ .NetworkSettings.IPAddress }}' mysql

最後まで行くと LocalSettings.php 入れてねって言われます。

local settings

今回は oauth extension をとにかく早く動かしたかったので mail 系を全部無効にしました (しないと認証求められるので)

$wgEnableEmail = false;
$wgEnableUserEmail = false; # UPO

...

$wgEmailAuthentication = false;

入れます

$ docker cp ./LocalSettings.php mediawiki:/var/www/html/

oauth extension

OAuth extension を download してきます
ここら辺です

Download MediaWiki extension - MediaWiki

適当なところに copy して解凍します

$ docker cp ./OAuth-*.tar.gz mediawiki:/tmp/
$ docker exec mediawiki tar xzf /tmp/OAuth-*.tar.gz -C /var/www/html/extensions

LocalSettings.php に設定を追記して update します
とりあえず誰でも consumer を追加できるようにしたいのでそんな感じにします

$ docker exec mediawiki sh -c "echo \"wfLoadExtension( 'OAuth' );\" >> /var/www/html/LocalSettings.php"
$ docker exec mediawiki bash -c "echo $'\$wgGroupPermissions[\'user\'][\'mwoauthproposeconsumer\'] = true;' >> /var/www/html/LocalSettings.php"
$ docker exec mediawiki php /var/www/html/maintenance/update.php

consumer registration は http://localhost:8080/index.php/Special:OAuthConsumerRegistration