2017年01月30日

JavaScript無しでハンバーガーメニューを実装してみた(けど、恐らく使うべきではない)

諸事情でJavaScript無しでハンバーガーメニューを実装する必要が出た。つまり、メニュー表示用アイコンを準備し、それがクリックされた時にメニューを表示するという実装。JS無しですってよ奥様。いやいや無理だろ。

ダメ元で調べてみると……いやぁ何事もググってみるもので、CSSのみでマウスクリックを検知し、ページに変化を起こさせるサンプルが見つかった。

続きを読む
posted by 天井冴太 at 00:32| Comment(0) | TrackBack(0) | Hack | 更新情報をチェックする

2016年05月24日

cronでnotify-sendを使う(GNOME環境以外で!)

Linuxで定期的にプログラムを動かす時にはcronと呼ばれる仕組みを使う。また、デスクトップ上に通知バルーンを出すには`notify-send`というコマンドが使える。これらを組み合わせれば、画面上に定期的に通知を出せる筈だ。

ところが、コレがなかなか上手く行かない。 `crontab -e` で直接`notify-send`を指定しても、`notify-send`を呼び出すシェルスクリプトを指定してもダメ。調べてみると、単純に`notify-send`を使うだけではダメなようだ。cronで呼び出されるプログラムは、古き良きCUIプログラムである事が前提で云々。

ググると何通りかの回避策が出てくる。が、試した幾つかは上手く行かなかった。もしかしたら同じように悩んでいる人が居るかもしれないし、以下に纏める。

続きを読む
ラベル:Linux cron notify-send
posted by 天井冴太 at 00:29| Comment(0) | TrackBack(0) | Hack | 更新情報をチェックする

2012年07月19日

Yahoo! Pipesのtips的な何か

Pipesの用語がイマイチ分かってない。Moduleの名称や作成画面左下の説明文から推察して使ってる。

既存sourceに別のelementを足す

既存のsourceに、別のelementを足したい時。

Item BuilderとUnionを使うと別のelementになってしまう。[Yahoo!Pipesで既存sourceに別のelementを足す: Item BuilderとUnionでは、別のelementになってしまう]

正解はRenameとRegexを使う。先ずRenameで挿入先sourceの適当なelementをCopy Asし、次にその要素の中身をRegexで入れ替える。[Yahoo!Pipesで既存sourceに別のelementを足す: Renameでelementをコピー(Copy As)し、その値全体をRegexで書き換える(replace [^.*$] with [追加する値])と上手く行く

或るelement内のtextに別のtextを連結する

取得したURLに別のqueryを追加したい場合とか。

Regexを使う。適当なタグ(例図では"//TAG//")を決めて、それの追加、置換という順で処理。[Yahoo!Pipesで或るelement内のtextに別のtextを連結する: 連結位置にタグを追加(replace [^(.*)$] with [$1タグ文字列])し、そのタグを置換(replace [タグ文字列] with [連結したい文字列])するという手順をとる]


うーん、「痒い所に手が届く」ようなModuleが足りない。上に挙げた手もこうやってメモっとかないと1週間後には何故こうしてるのか忘れてそうだ。個人的にはelementの値をtextで取得する手段が欲しい。あとコメントを付ける手段。何かそれを実現するトリックとか在るんだろうか?

あと、Pipesって文字列で表現出来ないからテキストで書きにくいね

ラベル:pipes
posted by 天井冴太 at 20:11| Comment(0) | TrackBack(0) | Hack | 更新情報をチェックする

2011年05月22日

型の擬似的な上書き ――BOOST_AUTO_TEST_CASE_FIXTUREの仕組みより――

個人的に目から鱗だったのでメモ。

Boost.Testsetup/teardown的な物を書くにはどうすれば良いのかなーとググって、IT戦記のコメント欄経由でBOOST_FIXTURE_TEST_SUITE()の存在を知る。
で、ふと該当部分のコードがどうなってるのか気になったので覗いてみた。

以下引用コードは全てBoost 1.45.0のunit_test_suite.hppから。

#define BOOST_FIXTURE_TEST_SUITE( suite_name, F )					   \
BOOST_AUTO_TEST_SUITE( suite_name )									 \
typedef F BOOST_AUTO_TEST_CASE_FIXTURE;								 \
/**/

53~56行、BOOST_FIXTURE_TEST_SUITE()マクロの定義部分。このマクロの第2引数に指定したクラスがfixture実装クラスとなり、コンストラクタがsetup処理、デストラクタがteardown処理になる。利用法は上に挙げたメモの日々(2009-05-26)を参照。

さて、このコードを見ると、fixtureを使わない場合に使用するBOOST_AUTO_TEST_SUITE()を内部で利用している。BOOST_AUTO_TEST_SUITE()は44~47行にて定義されており、次のようになっている。

#define BOOST_AUTO_TEST_SUITE( suite_name )							 \
namespace suite_name {												  \
BOOST_AUTO_TU_REGISTRAR( suite_name )( BOOST_STRINGIZE( suite_name ) ); \
/**/

で、実際のテストケースを記述するBOOST_AUTO_TEST_CASE()マクロは次のように定義されている。114~116行。

#define BOOST_AUTO_TEST_CASE( test_name )							   \
BOOST_FIXTURE_TEST_CASE( test_name, BOOST_AUTO_TEST_CASE_FIXTURE )
/**/

BOOST_FIXTURE_TEST_SUITE()の定義内にてtypedefされているBOOST_AUTO_TEST_CASE_FIXTUREが此処で利用されている。
……あれ?でもこれってBOOST_AUTO_TEST_SUITE()利用時には定義されていない筈だよな?一体どうなってるんだろう?

"BOOST_AUTO_TEST_CASE_FIXTURE"でコード内を検索すると、以下の記述が見つかる。193~202行。

namespace boost { namespace unit_test { namespace ut_detail {

struct nil_t {};

} // namespace ut_detail
} // unit_test
} // namespace boost

// Intentionally is in global namespace, so that FIXURE_TEST_SUITE can reset it in user code.
typedef ::boost::unit_test::ut_detail::nil_t BOOST_AUTO_TEST_CASE_FIXTURE;

グローバルスコープにて全く同じ名前の型がtypedefされている。

つまり、BOOST_AUTO_TEST_SUITE()使用時は、

typedef ::boost::unit_test::ut_detail::nil_t BOOST_AUTO_TEST_CASE_FIXTURE;

namespace test_suite_name {
// 略
BOOST_FIXTURE_TEST_CASE(test_case_name, BOOST_AUTO_TEST_CASE_FIXTURE); // グローバルの物が使われる
// 略

……のように展開され、グローバルスコープに定義されたBOOST_AUTO_TEST_CASE_FIXTUREが利用される。

が、対してBOOST_FIXTURE_TEST_SUITE()使用時は、

typedef ::boost::unit_test::ut_detail::nil_t BOOST_AUTO_TEST_CASE_FIXTURE;

namespace test_suite_name {
typedef fixture_class_name BOOST_AUTO_TEST_CASE_FIXTURE;
// 略
BOOST_FIXTURE_TEST_CASE(test_case_name, BOOST_AUTO_TEST_CASE_FIXTURE); // 同じ名前空間内の物が使われる
// 略

……のように展開され、名前空間内のtypedefに因ってグローバルスコープのBOOST_AUTO_TEST_CASE_FIXTUREが隠蔽されるようになっているのである。

確かに、このような場合には、より内側の物で外側が隠蔽されると入門書で読んだ記憶があるが、実際に使われているコードを見るのは初めてかも。

目から鱗というか、盲点だったというか。

setup/teardown
それぞれ、テスト開始時に必ず行う処理、テスト終了時に必ず行う処理
Boost 1.45.0
2011年5月22日現在、最新のバージョンは1.46.1だが、ものぐさこいてアップデートしてなかった……
ラベル:C++ boost Boost.Test
posted by 天井冴太 at 04:05| Comment(0) | TrackBack(0) | Hack | 更新情報をチェックする

2010年04月22日

Seesaaブログの独自タグ <% if %> で、論理演算する方法

……を、ずーっと考えてた。
結論、算術演算で何とかなる。

このblogが利用しているblogホスティングサービス、Seesaaブログでは、かなり柔軟なカスタマイズが可能となっている。どれくらいかというと、HTMLを丸ごと書き換える事さえ出来るぐらいだ。

HTMLを書き換える際には、その中にSeesaaブログ独自のタグを埋め込む事になる。『ここにタイトルを入れる』『ここに記事を列挙する』といった指定をするのに。一種のDSLだ。

条件分岐をさせようとした場合、Seesaaブログの独自タグでは次のように書く。


<% if:EXPRESSION %>
  <!-- ここにEXPRESSIONが真の時の内容を記述する -->
<% /if %>

例えば、次のように書く。


<% if:page_name eq 'index' %>
  <p>このパラグラフは、blogのトップページでのみ出力される</p>
<% /if %>

ところが、EXPRESSIONには、複数の条件をAND/OR下ものを書く事が出来ない。例えば、次のような記述は許可されない(そして、パース処理がエラーを吐く為か、何も表示されない)。


<% if:page_name eq 'index' & page_name eq 'archive' %>
  <p>トップページか、過去ログのページで表示させたい。</p>
  <p>……が、上手くいかない。</p>
<% /if %>

<% if:page_name eq 'index' and page_name eq 'archive' %>
  <p>"and"と書いてもダメ。</p>
<% /if %>

<% if:((page_name eq 'index') and (page_name eq 'archive')) %>
  <p>括弧で囲ってもどうにもならない。</p>
<% /if %>

……さてどうしよう?

実は、独自タグ内では算術演算が可能だ。何処まで可能なのか、ハッキリと調べた訳ではないが、加算(+);、減算(-)、乗算(*)が可能なのは確認した。

後は、その特性を利用して、次のように書ける事が分かる。


<!-- 論理和(or) -->
<% if:((page_name eq 'index') + (page_name eq 'archive')) %>
  <!-- snip -->
<% /if %>

<!-- 論理積(or) -->
<% if:((page_name eq 'archive') * (archive_page_name ne 'mday')) %>
  <!-- snip -->
<% /if %>

否定(not)はちょっと思いつかない。page_name eq 'index'page_name ne 'index'のような、条件を逆にする手法ぐらいだろうか。

ラベル:seesaaブログ
posted by 天井冴太 at 04:10| Comment(0) | TrackBack(2) | Hack | 更新情報をチェックする

2006年11月16日

長い文字列を自動的に途中改行させるようにするJavaScript - Firefoxで長い文字列が改行されない件を回避しようとして翻弄された話

先日MSに翻弄された話をポストし、お気に入りのブラウザであるFirefoxで実際に表示させてみて卒倒しそうになった。
URLの部分が改行されない為、tableがとんでもなく見難い状態になっていた。

Firefoxは半角英数記号文字列を途中改行しない仕様だというのは知っていたが、今までは(多少見難くなっても)閲覧にはそれほど影響無いと判断して特に対策は行ってなかった。どうしても気になる人はurl_breaker辺りで対策してね、という事で。

しかし今回のは酷すぎる。何とか対策をしないと。

JavaScriptで自動処理だ!!

此処まで閲覧に支障があるのならばサイト側で対策したい。上記拡張のGreaseMonkey版であるurl_breaker_plusを見つけたので、それをそのまま関数化→loadイベントで呼び出せばいいだろう。

url_breakerやurl_breaker_plusの仕様は記号文字毎にwbr要素を挿入する、というもの。wbr要素はIEとMozilla系ブラウザが独自に実装している要素で、HTML/XHTML標準規格のものではない。それがチョット気になるが、まぁ、仕方ない。

という訳でurl_breaker_plusのコードをチョイチョイと弄って実装した。
よしよし、ちゃんと改行されるように……




あるぇ?
table内の文字列が改行されない!?なんでー??

そして苦難の道が続く

ソースを見てみると、間違いなくwbr要素が挿入されている。……のに改行されない。ワケが分からん。

url_breakerのページを見てみると、

Ver.0.2.5 (2006/06/17~08/05) ((略)) loadイベントではなくDOMContentLoadedイベントを利用することで、 table内などで折り返しができない問題を若干改善

という記述を発見。……DOMContentLoadedイベント?調べてみると、Collection &\1 Copy - ドキュメントのロード完了に合わせて関数を実行するというページを発見。曰く、「ドキュメントのロードが終わっていて、かつ、イメージのロードが完了する前」に発生するFirefoxの非標準イベントらしい。試しに変更してみる。……駄目だ。上手くいかない。まぁ、url_breakerのページでも若干改善 としか言っていないし。

Bookmarkletだと上手くいく

念の為url_breakerやurl_breaker_plusをインストールして確認してみたが、やはりtable要素内はwbrが挿入されるのに改行されない。まさに若干改善若干外の問題にブチ当たってしまったようだ。

途方に暮れながらwebの大海を彷徨っていると、Wrap!というBookmarkletを公開している人が居た。駄目元で使ってみると……あれ?table内も改行される……?

よぉし希望が見えてきたぞ。じゃぁコッチのコードを元にしてみよう。やはり関数化してloadやDOMContentLoadedイベントにdocument.addEventListenerする。
……あれ?今度は改行されなくなった……

オフラインだと上手くいく

bookmarkletだと上手くいって、loadやDOMContentLoadedイベントで実行するとtable内で上手くいかない。こうもワケワカラン状況になるとは……長くなりそうなので、検証用にMSに翻弄された話HDに保存……あ、間違えて保存したページ開いちゃった。




……………………あるぇ!!?
ローカルに保存したページだと改行が上手くいく。

色々実験。どうやら下に付けているCallbeeのフィードリーダが原因のようだ。外してみたらurl_breakerを元にしたコードもWrap!を元にしたコードも上手くいくし、外部サイト(このblogのページの読込が終わった後?)の読込が絡むと上手くいかないんじゃないかと予想。

何とか解決

という事は、外部サイトのリソースも全て読み込み終わってから処理すると上手くいくという事か。成る程Bookmarkletだと上手く行く訳だ。

少し悩んだが、body要素の閉じタグ直前にscript要素でスクリプトを読み込み、実行するようにした。なお、url_breakerを元にしたコードは最後にdocument.style.width = '100%'; focus();としないと上手くいかなかった

で、実装

記号毎にwbrを文字の前に挿入するか後に挿入するか変える事が出来るWrap!を元に実装。ついでにurl_breakerの指定文字数で強制的に折り返すを参考に、強制改行(br要素の挿入)では無くwbrを挿入するようにしてみた。

……で、出来上がったのがコレ。なにやら謎な分岐があるけど、それについては今度(多分)纏めます。

…………バグにとっつかまって1週間も掛かったのはヒミツだwww

GreaseMonkey
コレの事。Firefoxの拡張機能で、JavaScriptで色々なサイトに手を加える事が出来るという大変便利なもの。ユーザCSSのJavaScript版といった感じか。
ソースを見てみると
今回色々試して気づいたのだが、Firefox(ver2.0 Windows,日本語版。他は分かんね)の『選択した部分のソースを表示』はJavaScriptとかで処理した後のコードを見る事が出来る。
url_breakerを元にしたコードは最後にdocument.style.width = '100%'; focus();としないと上手くいかなかった
恐らく、bookmarklet: Wrap! ― 長い1byte文字列を折り返す(Mozilla) - airhead の日記で述べられている折り返し候補位置すべてにWBR要素を挿入してもそれだけではTABLE要素サイズの再計算は行われないので、BODY要素の幅を再設定してドキュメント領域の幅にあわせた折り返しを促しているが原因だろう。
posted by 天井冴太 at 22:53| Comment(2) | TrackBack(1) | Hack | 更新情報をチェックする

2006年08月17日

新しいMSDNライブラリを呼び……出せない!?

……という訳で、前回の続きである。アレから10日も書かんで何やっとったか!!という不満は山の向こうにポイして頂きたい。


…………イヤほんとすみません。

VSIDEから呼び出して……アレレ?

前回インストールした新しいMSDNライブラリである2006年6月版(以降新ライブラリと呼ぶ)。 "スタート メニュー\プログラム\Microsoft Developer Network"下にショートカットが作成される。VSEE添付のライブラリ(以下旧ライブラリと呼ぶ)とは大違い。
起動すると新ライブラリのホームページが表示される。
…………問題なくインストールされているようだ。

ではIDEから呼び出してみよう。[ヘルプ]→[カテゴリから検索]。よし、ちゃんと呼び出せて……
…………あ、あれぇ?これって旧ライブラリの方じゃん!!

続きを読む
ラベル:MSDN
posted by 天井冴太 at 14:29| Comment(0) | TrackBack(0) | Hack | 更新情報をチェックする

2006年07月29日

GUI上でもCUI上でもソレっぽく使えるWSH用入力関数を作ってみた。

JScript書いてて困った。

今までWSHでの開発にはVBScriptを使っていたが、だんだん面倒になってきた。というかIfとかForとか、頭文字の大文字にわざわざShift押すのがメンドクサイ。じゃあって事でWSH標準で使えるもう一つの言語、JScriptでコードを書いてみた

さて、途中でユーザの入力を受け取る必要が在った訳だが、『JScriptなんてしょせんJavaScriptクローン』と思っていた私は迷うことなく次のようなコードを書いた。

result = prompt('入力してください', '規定値');

……あれー、エラーになるー?
MSDNライブラリやWSHのヘルプを調べてみると、WSH上のJScriptにはprompt()は用意されていない模様。同等の働きをする関数も無い
ちょ、JScript使えねー。うーん、やっぱVBScript使うかなぁ。

しかし此処でふと思った。そういえばWSHの標準出力メソッドであるWScript.EchoGUI上でのアイコンダブルクリック等での実行の時はダイアログボックスで、CUI上でCSCRIPTコマンドで実行した場合はコマンドプロンプトの標準出力でと場合によってより相応しい方法での出力となる何で入力はそういう『場合分け』出来るメソッドが無いんだろう?

という訳でサクッと作ってみたのがinput.vbs。どうぞ煮るなり焼くなり御自由に。

var result;
result = aslib_input("プロンプト文字列", "デフォルト値");

プロンプト文字列を表示してキー入力待ち、入力内容が戻り値となる。何も入力しないでEnter押した場合はデフォルト値に設定したものが返る。あー、こういう時って変数がバリアント型な言語だと楽だなぁ。

本当はVBScriptInputBox()並みに高機能にしたかった……てか入力待ちの時間を制限するなんてWSHで出来るのか?

WScript.FullNameで実行エンジンがGUI(WSCRIPT使用)かCUI(CSCRIPT使用)かを調べ、それぞれInputBox()か、WScript.StdOut.Write()WScript.StdIn.ReadLine()のあわせ技かを切り替えている。うーん、GUICUIかの判定に『エンジン名を調べる』という方法しか取れなかったのが残念。WSCRIPT.EXE、CSCRIPT.EXE以外の第3のエンジンが在った場合判定しようが無いじゃないか。取り合えず『知らないエンジン名だったらエラー投げる』という仕様にしてある。

使う場合はスクリプト自体をWindows スクリプト ファイルにして<script>要素で読み込む必要が在る。

<?xml version="1.0" ?>
<package>
    <job id="testInput">
        <script language="VBScript" src="input.vbs"></script>
        <script language="JScript">
        <![CDATA[
        var res = input("prompt", "title", "default");
        WScript.Echo(res);
        ]]>
        </script>
    </job>
</package>
頭文字の大文字にわざわざShift押すのがメンドクサイ
VBScriptは大文字と小文字を区別しないのでどちらかだけで書けば良いだけの話なのだが。やっぱり、そこは、ねぇ?きちんとしたくならない?
JScriptでコードを書いてみた

今まで何でJScript使ってなかったのかというと、VBScriptCreateObject()に相当するものがActiveXObjectなんてそのものずばり過ぎる名前だった事。JavaScriptパクリ言語のイメージが有った事が原因。

ところで前者はWScript.CreateObject()を使う事で解決。……これって、VBScriptCreateObject()、JScriptのActiveXObjectとはまた別のものなのだろうか?

ラベル:WSH VBScript JScript GUI CUI
posted by 天井冴太 at 19:04| Comment(0) | TrackBack(0) | Hack | 更新情報をチェックする

2006年03月09日

IDEで不自然でないtypedefの方法――CでC++的なユーザ定義型の宣言を!!

C言語のユーザ定義型において、それが『どのタイプのユーザ定義型なのか』という情報はその型のオブジェクトを作る際に必要になる。

つまり、次のようなC/C++のコードがあったとして、


struct Hoge {
	int foo;
	int bar;
};

このHoge型のオブジェクトの作り方は少し違う、というオハナシ。


struct Hoge hoge;	// C言語の場合; "struct"の部分が必須

Hoge hoge;	// C++の場合; "struct"は無くてもいい

でもさ、C言語でオブジェクト宣言時にstructとかunionとかenumとワザワザ打ちたくない!!C++っぽく出来ないの!?

続きを読む
ラベル:C
posted by 天井冴太 at 23:45| Comment(0) | TrackBack(0) | Hack | 更新情報をチェックする

2005年08月23日

BASICのMID$()をC++で再現してみる

いろいろPCのトラブルとか暇無いとか忘れてたとかで、やっと記事第1号を書く事になった。いや忘れてたは無いだろ忘れてたは、とか言うツッコミを期待恐れながら、記念すべき第1号記事を書いてみたいと思う。

閑話休題。
さて、第1号記事の内容はこのblog作った当初から決めていて、『BASICMID$()をC++で再現する』というものだ。ネタ元はcppllの投稿『[cppll:11798] BASIC の MID$』。

一部のBASIC実装に在ったMID$()という関数をC++で実装するには?というもの。この関数、ただの関数ではなく代入の左辺に使うことも出来る

10 STR$ = "hogehoge"
20 RES$ = MID$(STR$, 3, 4) ' STR$の(1バイト文字単位で)3文字目から4文字取得
30 PRINT RES$
40 MID$(STR$, 3, 4) = "PIYO" ' STR$の3文字目から4文字をPIYOに変える
50 PRINT STR$
geho
hoPIYOge

20行のようなものは普通に書ける(というか普通の関数はこういう仕様)が、40のようなものを書けるようにする為には……?

早速思いついたので書いてみたのがこれ

class Mid;

class MidSub {
    std::string &str_;
    std::string::size_type start_, len_;
public:
    MidSub(std::string &to, std::string::size_type start,
           std::string::size_type len) :
        str_(to), start_(start), len_(len) { };

    std::string &operator=(std::string &from) {
        // 略
    }

    operator std::string() {
        // 略
    }
};

class Mid {
public:
    MidSub operator() (std::string &to, std::string::size_type start,
        std::string::size_type len) {
        return MidSub(to, start - 1, len);
    }
} mid;

mid.operator()()で処理用オブジェクトMidSubを生成するようになっている。何でこんな回りくどい事になっているかというと、mid(str, 1, 2) = "ほげ"の場合、普通にやるとmid(str, 1, 2)(多分operator()になるだろう)の戻り値に"ほげ"を代入する、という変な処理となってしまう為だ。

しかし、どうも『Midが実質的に何もしていない』『midがインスタンス』という点が気持ち悪いように思っていた。

ある日、C++を猛勉強していた専門学校でのクラスメートYに(ネタとして)見せていると、偶然通りかかったM先生の目に止まる。

天井冴太『~でキモチワルイんですけど、どうにかなりませんかねぇ。』
M先生『なるよ』
天井冴太『(゚д゚)ナンダッテー』

いろいろ話をして、思いついたのがこれ

class mid {
    std::string &str_;
    std::string::size_type start_, len_;

public:
    mid(std::string &str, std::string::size_type start,
        std::string::size_type len = std::string::npos)
        : str_(str), start_(start - 1), len_(len) {
        // 略
    }

    std::string &operator=(const std::string &from) { // [mid() = string] ver
        // 略
    }

    operator std::string() const { // [string = mid()] ver
        // 略
    }
};

mid()一時オブジェクト生成のシンタックスを利用するようにした。よくよく考えたら関数のシンタックスと同じなんじゃないか、これって。これによって、midを1つのクラスにまとめる事が出来た。

ひとつ残念だったのは、グローバルなoperator=()が記述できない点。どうやら言語仕様上そうなっているらしい。operator=(std::string, mid)を定義出来たらスッキリしたのだが……仕方が無いのでoperator std::string()を使っている。なので、下手したらキャストする必要が出てきてしまうが、それはまぁ、ご愛嬌という事で。

続きを読む
ラベル:C++
posted by 天井冴太 at 21:19| Comment(0) | TrackBack(0) | Hack | 更新情報をチェックする

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。