はじめてはてなブログを使ってみようと思います。
普段技術ネタをQiitaにあげているのですが、技術ネタではないものを書くためにこのブログを開設しました。shirajiともうします。
Qiitaもshirajiというアカウントで記載しておりますので、そちらも確認してください。
思ったものを記載していくつもりです。更新ペースはそこまで高くないです。
よろしくお願いいたします。
最近、Objective-cやらJavaやらRailsやらPlay frameworkやら手を出しまくっているせいか書くネタがない。。。
ということで、本題。
端末をかえることが重なってしまい、毎回Eclipseの設定をするという非常にだるいことになったので、一旦、何を毎回しているかメモ書き。あくまで自分の環境なので、設定して壊われても責任持ちません。
(いい加減、このあたりなんとかならないものか・・・。vimのvundleみたいにファイル一つでやってくれたらいいのに。)
1. インストール
面倒なので、All in one(Android開発ならADT)
URL: http://mergedoc.sourceforge.jp/
重い場合は新しいPC買えばいいと思う。(自分はお金がないので我慢。)
2. 英語化
URL: http://d.hatena.ne.jp/shiraji/20130427/1367054426
3. プラグイン
4. 補完
5. UTF-8化
ファイルのエンコーディングをUTF-8にする。てかこれなんでデフォルトじゃないのだろう?
6. キーバインド
設定する場所: Window > Preferences > General > Keys
Name:「Open Glance」
Binding: Ctrl+j
When:「In Dialogs and Windows」Name:「Next Match」
Binding; Ctrl+j
When:「Glance Search Context」上のキーバインドをコピーし、
Name:「Next Match」
Binding; Enter
When:「Glance Search Context」Name:「Previous Match」
Binding; Ctrl+Shift+j
When:「Glance Search Context」
Name:「Clean」
Binding; F8
When:「In Windows」
Name:「Toggle Toolbar」
Binding; Ctrl+4
When:「In Windows」
8. ツールバーのカスタマイズ
Eclipse Junoを使っている方(特にADT)この設定はやらないほうがいいです。理由は追記に記載。
9. コードテンプレート
/**
* {@inheritDoc}
*/
throw new UnsupportedOperationException("havn't implemented, yet");
10. その他
なんかまとめたら大作になた・・・。
設定関連はgithubにあげて管理しなきゃ。放置しているレポジトリがあるから、腰をあげてみますか。
にしてもこのブログのフォーマットうまくできない。
写真つきにしようと思ったら、かなり長くなったので、やめた。
// 追記 ////////////////////////////////////////////////
ツールバーの変更について
書いてから、気づいたのですが、現在ADTではツールバーにバグが存在しています。
ツールバーのアイコンの移動や消したものをもとに戻す機能にバグがあり、動かないと報告もあります。https://bugs.eclipse.org/bugs/show_bug.cgi?id=340695
もし、ツールバーからアイコン消したけど、やっぱり必要だったーなどがあった場合、以下のファイルを消すともとに戻ります。
workspace/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi
ただし、このファイルはビュー関連の設定が入っているファイルですので、消す場合、またパースペクティブなどのレイアウトをし直す必要があります。扱いには細心の注意を払って下さい。
10月くらいからObjective-cを触っている。
結構毎日触っているんだけど、まだまだわからないことが多くて大変です。
さらにプライベートではwindows使っていて、Mac持っていないので、会社でしか触れていなくて。Mac買おうかなー。
ということで初歩的なところではまったのでメモ。
// 配列
NSArray array = @[@"赤",@"青",@"黄",nil];for (NSIntger index = -1; index < [array count]; index++) {
if (index > 0) {
NSLog(@"%@", [array objectAtIndex:index]);
} else {
NSLog(@"%@", @"以下から選んで下さい。");
}
}
こんな感じで、ループさせてみた。まぁなにゆえ、ループ前にやらないのかとかあるけど、とりあえずそこはおいておいて。
このループ実は実行されない。なぜかというと[array count]の戻り値がNSUInteger。つまり、unsigned integer。
index=-1を比較する場合、indexがunsigned integerとして扱われ、-1はunsigned integerの一番大きな数字となる。
Javaにはないunsigned型があるので注意しましょうということでした。
以前からJenkinsさんをchefで立ち上げるところまで自動化したのですが、
Jenkinsさんの自動起動が設定されていなかった。
ドキュメントを流し読みしてみても、Jenkinsさんの自動起動設定がない。
じゃあそういうレシピ作成してみよかと思ったのですが、数カ月前ということもあり、完全に失念!
ということで、chefのcookbook作成方法のメモです。
まず、環境を作る。
git clone https://github.com/shiraji/chef-repo.gitこれで問題なければ、今回使うchefやknifeが入る。
cd $HOME/chef-repo
bash chef_setup.sh
以前にも書いたと思うけど、ざっくり構成についておさらい。
chef-repo/nodesとrolesはかなり重要で、この2つを意識したcookbookを作れば、拡張性が高くなる。
├── cookbooks --- 人が作ったcookbooksを保持
├── nodes --- 実行される各サーバ固有の設定を保持
├── roles --- cookbook利用時の設定値を保持
└── site-cookbooks --- 自分が作成したcookbookを保持
├── addusers --- 自作ユーザ追加cookbook
└── server_settings --- 自作サーバの基本設定のcookbook
実際にcookbookを作成してみる。
cd $HOME/chef-repo/site-cookbooks/knifeが色々揃えてくれた結果がこれ
knife cookbook create autorun_settings -o .
site-cookbooks/Hello worldしてみる。
└── autorun_settings
├── CHANGELOG.md
├── README.md
├── attributes --- attributeを設定する。default.rbがデフォルトの値
├── definitions
├── files
│ └── default
├── libraries
├── metadata.rb
├── providers
├── recipes
│ └── default.rb --- デフォルトのrecipe
├── resources
└── templates
└── default
デフォルトのrecipe(recipes/default.rb)に以下を書き込む。
puts "Hello World"これだけでほぼ終わりなのだけど、せっかくなので、nodes, rolesを設定する。
まずはrole。$HOME/chef-repo/roles/にjenkins_autorun.jsonを作成する。
本当はここで、knife role createとかするべきなんだけど、knifeの設定してないしーということで簡単なスクリプト作成したので、それを利用して、作成する。
cd $HOME/chef-repo/roles/new_role.shはsedでテンプレートファイルの中身を変更し、それをファイルに保存している。
bash new_role.sh jenkins_autorun.json
#!/bin/shrole_template.jsonはknife create roleすると出来るべきroleファイルif [ $# -ne 1 ]; then
echo "No role name"
exit 1
fi_role_name=$1
cat role_template.json | sed -e "s/NAME/${_role_name}/g" > ./${_role_name}.json
{上記のコマンド叩いて、出来るのがこのrole。(コピペするだけでも問題ない。)
"name": "NAME",
"description": "",
"json_class": "Chef::Role",
"default_attributes": {
},
"override_attributes": {
},
"chef_type": "role",
"run_list": [],
"env_run_lists": {
}
}
{今のところ、attributesなどはないので、設定せず、run_listに先程作成したcookbookを設定する。
"name": "jenkins_autorun",
"description": "",
"json_class": "Chef::Role",
"default_attributes": {
},
"override_attributes": {
},
"chef_type": "role",
"run_list": [],
"env_run_lists": {
}
}
{次にnode
"name": "jenkins_autorun",
"description": "",
"json_class": "Chef::Role",
"default_attributes": {
},
"override_attributes": {
},
"chef_type": "role",
"run_list": [
"recipe[autorun_settings]"
],
"env_run_lists": {
}
}
{実行で必要な設定ファイル(chef-repo/solo.rb)はこんな感じ。
"run_list": [
"role[jenkins_autorun]"
]
}
le_cache_path "#{ENV['HOME']}/chef-repo"$HOME直下に置いてあると想定されている。違う所に置いてある場合は、このファイルを変更すること。
data_bag_path "#{ENV['HOME']}/chef-repo/data_bags"
encrypted_data_bag_secret "#{ENV['HOME']}/chef-repo/data_bag_key"
cookbook_path [ "#{ENV['HOME']}/chef-repo/site-cookbooks",
"#{ENV['HOME']}/chef-repo/cookbooks" ]
role_path "#{ENV['HOME']}/chef-repo/roles"
それでは実行
cd $HOME/chef-repo実行結果
chef-solo -c solo.rb -j nodes/jenkins_autorun.json
Starting Chef Client, version 11.6.0これで、Hello Worldはできたので、今回の目的であるjenkinsのサービスの自動起動をしてみる。
Compiling Cookbooks...
Hello World
Converging 0 resources
Chef Client finished, 0 resources updated
execute "autorun" doただ、これだと、jenkinsのみのcookbookになってしまう。そこでattributeを設定し、roleで指定できるようにする。
command "chkconfig jenkins on"
action :run
end
default[:autorun][:ons] = ["jenkins"]これを使うrecipeはこんな感じ。
node[:autorun][:ons].each do |on|実際に実行してみると
if !on.empty?
execute "autorun on" do
command "chkconfig #{on} on"
action :run
end
end
end
Starting Chef Client, version 11.6.0これでもまだ、拡張性がないので、autorunの設定のON、OFFができるようにする。
Compiling Cookbooks...
Converging 1 resources
Recipe: autorun_settings::default
* execute[autorun on] action run
- execute chkconfig jenkins on
Chef Client finished, 1 resources updated
default[:autorun][:ons] = []デフォルトのrecipeを以下に
default[:autorun][:offs] = []
node[:autorun][:ons].each do |on|ここで、roleでoverride_attributesを設定する。chef-repo/roles/jenkins_autorun.jsonを以下のようにする。
if !on.empty?
execute "autorun on" do
command "chkconfig #{on} on"
action :run
end
end
endnode[:autorun][:offs].each do |off|
if !off.empty?
execute "autorun off" do
command "chkconfig #{off} off"
action :run
end
end
end
{実行結果(上記と同じ)
"name": "jenkins_autorun",
"description": "",
"json_class": "Chef::Role",
"default_attributes": {
},
"override_attributes": {
"autorun": {
"ons": ["jenkins"]
}
},
"chef_type": "role",
"run_list": [
"recipe[autorun_settings]"
],
"env_run_lists": {
}
}
Starting Chef Client, version 11.6.0これで完了。
Compiling Cookbooks...
Converging 1 resources
Recipe: autorun_settings::default
* execute[autorun on] action run
- execute chkconfig jenkins on
Chef Client finished, 1 resources updated
■注意点■
私は今CentOSの環境のみしかないので、chkconfigが使えないubuntuとか気にしていない。
必要な場合はOS別のコマンドを作成すればいいと思う。
crontabは恐ろしいオプションがあるとそこらじゅうのブログで見ていて、crontab -eもしないようにcrontab file_nameで設定するように心がけていました。
で、いざやっていると、crontab file_nameの後ってうんともすんとも言わんのです。
こんな感じです。
[shiraji ~]% cat test.crontab本当に設定できたの?と毎回crontab -lをするはめに。
0 0 * * * /bin/bash /tmp/test.sh
[shiraji ~]% crontab test.crontab ### ★ここで何も言わない
[shiraji ~]% crontab -l
0 0 * * * /bin/bash /tmp/test.sh
[shiraji ~]%
てかcrontabなんて使わずに、Jenkins使えばいいと思う。
以前のエントリー:Thorを使ってみた(Rubyバッチ編)
いくつかRailsのバッチを書いていて、共通な部分が結構あったので、クラスとして出して、使いやすくしてみました。
やっていること:
■注意点
Railsの環境設定を行っているため、Thor::Invocation.invoke_commandを継承している。
Thorの更新が入った場合、invoke_commandメソッドの呼ぶタイミングが変更されるかも?
Thor.invoke_command
Thor.dispath
Thor.start
などを参照してみてください。
■使い方
前のTestバッチ
class Test < Thor
class_option :help, :type => :boolean, :aliases => '-h', :desc => 'Thor test'
default_task :execute
desc "execute [OPTION]", "Test execute"
option :production, :type => :boolean, :aliases => '-p', :desc => "Run production DB server"
option :number, :type => :numeric, :aliases => '-n', :default => 3, :desc => "test number"def execute
# DBオプション
if options[:production] then
@mode = 'PRODUCTION'
else
@mode = 'DEVELOPMENT'
endputs @mode
puts options['number']
end
end
Test.start
MyThorを使ったバッチ。
class Test2 < MyThor
default_task :execute
desc "execute [OPTION]", "Test execute"
option :number, :type => :numeric, :aliases => '-n', :default => 3, :desc => "test number"def execute
puts Rails.env
puts options['number']
end
end
Test2.start
さらに簡単に。default_taskもMyThorに持っていくといいかもしれない。
===
はてなさんが直すのを待ち続けていたのですが、一向に直らないので、GistのCSSいじりました。多少見やすくなったのではないでしょうか。
コードが横に長いと行番号の横幅が無くなってしまい1行1桁しか表示されなくなってしまうのが問題でした。
デフォルトで!とおもったのですが、さすがに我慢できず。
今回はTextView!
半日悩んで解決したのでメモです。
条件
とりあえず簡単なやつから。
まずGoogleさんに判断させる部分だけど、
textView.setAutoLinkMask(Linkify.WEB_URLS);この一行でOK。あとはGoogleさんがよきに計らってくれる。
大半の条件はこれで満たせるのだけど、これだけでは確認ダイアログが付けられない。
タップするとアプリから勝手にブラウザに飛んで行ってしまう。
それでは条件満たせないので、それぞれのリンクに確認ダイアログをつけることにする。
そしてここから泥沼へ。
それぞれのリンクはURLSpanというオブジェクトとして保管されている。(それすら今回初めて知りました)
このURLSpanのonClickメソッドを継承し、onClickメソッド内でダイアログ表示→OKならブラウザへで完成するはず。
しかし、残念ながら、TextViewのsetTextメソッドはfinalメソッドのため、継承できず、autoLinkの動きをかえることはできません!何か方法があれば教えてください。
ということで苦肉の策。。。
CharSequence text2 = textView.getText();
if( text2 instanceof Spannable ) {
Spannable spannable = (Spannable) text2;
URLSpan[] spans = spannable.getSpans(0, text2.length(), URLSpan.class);
for (URLSpan urlSpan : spans) {
int start = spannable.getSpanStart(urlSpan);
int end = spannable.getSpanEnd(urlSpan);
spannable.removeSpan(urlSpan);
spannable.setSpan(new MyURLSpan(urlSpan.getURL()), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
やってること
全体
MainActivity.java
package com.example.textviewsample;import android.app.Activity;
import android.os.Bundle;
import android.text.Spannable;
import android.text.Spanned;
import android.text.style.URLSpan;
import android.text.util.Linkify;
import android.view.Menu;
import android.widget.TextView;public class MainActivity extends Activity {
private static final String text = "やふる:http://yahoo.co.jp\nぐぐる:http://www.google.co.jp\nびんぐる:http://www.bing.com/";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView)this.findViewById(R.id.textview);
textView.setAutoLinkMask(Linkify.WEB_URLS);
textView.setText(text);
CharSequence text2 = textView.getText();
if( text2 instanceof Spannable ) {
Spannable spannable = (Spannable) text2;
URLSpan[] spans = spannable.getSpans(0, text2.length(), URLSpan.class);
for (URLSpan urlSpan : spans) {
int start = spannable.getSpanStart(urlSpan);
int end = spannable.getSpanEnd(urlSpan);
spannable.removeSpan(urlSpan);
spannable.setSpan(new MyURLSpan(urlSpan.getURL()), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}}
MyURLSpan.java
package com.example.textviewsample;import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Parcel;
import android.text.style.URLSpan;
import android.view.View;public class MyURLSpan extends URLSpan {
public MyURLSpan(Parcel src) {
super(src);
}public MyURLSpan(String url) {
super(url);
}@Override
public void onClick(final View widget) {
AlertDialog.Builder builder = new AlertDialog.Builder(widget.getContext());
builder.setTitle("確認");
builder.setMessage(getURL()+"へ飛びますか?");
builder.setPositiveButton("おっけー", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
onClickSuper(widget);
}
});
builder.setNegativeButton("やだ", null);
builder.show();
}
private void onClickSuper(View widget) {
super.onClick(widget);
}
}
activity_main.xml
何が驚いたって、textView.getText()がString以外のもの返すこと。
CharSequenceのことを全く気にせずStringしか使ってこなかった自分が恥ずかしい。
MyURLSpan込みのTextViewを作成してみたい!がんばる。
今日はここまで。