Life, Education, Death

プログラミング以外でも思ったことをつらつらと書きたい

C++で型情報を持ったままにしておく

やりたいこと

型情報なしに管理したいがないと削除時に困る。削除時だけは型情報が欲しい。

コード

#include <iostream>

using namespace std;

class Foo
{
public:
    Foo()
    {
        cout << "Foo" << endl;
    }

    virtual ~Foo()
    {
        cout << "~Foo" << endl;
    }

protected:
    void *m_data;
};

template<typename T>
class Bar : public Foo
{
public:
    Bar()
    {
        cout << "Bar" << endl;
           m_data= new T;
    }

    virtual ~Bar()
    {
        delete reinterpret_cast<T*>(m_data);
        m_data = nullptr;

        cout << "~Bar" << endl;
    }
};


class Member
{
public:
    Member()
    {
        cout << "Member" << endl;
    }

    ~Member()
    {
        cout << "~Member" << endl;
    }   
};

int main()
{
    Bar<Member> bar;
}

出力結果

Foo
Member
Bar
~Member
~Bar
~Foo

呼び出し順も想定通りなのでこれでいいはず。

日本酒会201606その1

最近サボっていた定例会日本酒会を久々に開催。過去の会もそのうちまとめたいところ。

江戸川橋!初めて来た。よく探すなぁと予約してくれた人には感謝。 f:id:Nilfs:20160612220050j:plain

見たことある寿司が一つも出てこなかったぞ。酢飯

本日のメイン、予約してもらったお店は酢飯屋です。超美味しかった。

www.sumeshiya.com

酢飯屋ではこんなお酒をいただきました

飲んだことがないお酒ばかりですごく楽しかったです。3人で1合ずつもらったので結構種類も飲め満足です。振り返ると九州のお酒が多く、そもそも都内で見かけないものばかりのような気がします(観測範囲)。九州だと、天吹ぐらいしかすぐに出てこないです。

1つ目はたまゆら。長野県、橘倉(きつくら)という酒蔵のお酒です。スパークリング日本酒で日本酒苦手な人でも飲めそうなお酒です。 f:id:Nilfs:20160612182646j:plain f:id:Nilfs:20160612182826j:plain

www.kitsukura.co.jp

福岡、山口酒造。庭のうぐいす。 f:id:Nilfs:20160612204755j:plain

niwanouguisu.com

神奈川、泉橋酒造。黒蜻蛉。トンボのマークがかわいい。 f:id:Nilfs:20160612204836j:plain

izumibashi.com

夏やごっていうまた虫のラベルのお酒もあって虫が好きなのでしょうか・・・。 夏ヤゴ13 発売 | 泉橋酒造株式会社 Izumibashi SAKE Brewery.

熊本、花の香酒造。 f:id:Nilfs:20160612205024j:plain

www.hananoka.co.jp

熊本、墨守。瑞鷹という酒蔵。

f:id:Nilfs:20160612183101j:plain

www.zuiyo.co.jp

知らなかったですが造語ではなく存在する言葉のようで

自己の習慣や主張などを、かたく守って変えないこと。 だそうです。 墨守(ボクシュ)とは - コトバンク

料理はどれも見かけないものばかりでした

どれも美味しいし、話も面白いしいい体験だった。

最初はめかぶ。料理はそれぞれ解説があったのですがすぐにメモしてなかったのでところどころわからないものがあって残念です。

f:id:Nilfs:20160612182617j:plain

載っていたのは、からし菜の種の酢漬けだったはず。硬いので少しつけておいて柔らかくしているのとのこと。魚は石鯛

f:id:Nilfs:20160612182703j:plain f:id:Nilfs:20160612182717j:plain

魚の名前が思い出せなかったですが、2文字ぐらいだったような f:id:Nilfs:20160612182731j:plain

タカエビ。甘エビみたいにすごく甘かった記憶が。 f:id:Nilfs:20160612182744j:plain

名前が思い出せない貝の貝柱。すごいでかいですね。白たまりのみりん漬け。もともと真珠を取る貝で、地元でしか食べられていないものという説明でした。 f:id:Nilfs:20160612182755j:plain f:id:Nilfs:20160612182808j:plain

白たまりは、昔白醤油と呼ばれてたものらしく大豆ではなく小麦粉が多く入っているものだそうです。 使ったことがないので単体でどういう味だか、今度試してみたい。 日東醸造(愛知県碧南市) - 職人醤油

トビウオだったか、キビナゴだったかちょっと記憶が怪しいです。おからを巻いてあるものと外に置かれているのは別の魚と記憶しています。寿司の成り立ちとこの寿司について説明をしてくれて非常に勉強になります。 f:id:Nilfs:20160612182842j:plain

酢飯屋のページに詳しい事書いてありましたね。 キビナゴのおから寿司 / 郷土寿司プロジェクト / 酢飯屋 - 文京区水道、江戸川橋にある寿司、カフェ、ギャラリーの複合店

古代米と金目鯛。銚子で一本釣りをしたもので傷のない綺麗なものだそうです。傷の有無が魚の値段に大きく影響するらしくなかなかの高級魚だとか。30秒ぐらい噛むようにとの指示。噛めば噛むほど味が出る。 f:id:Nilfs:20160612213335j:plain

うー、マンボウマンボウのホルモンとサワラ。魚じゃなくて肉、ってかなんだこれは!と衝撃を受けた。比較的、ホルモンは日持ちするらしくどうにか食べれるそうです。 f:id:Nilfs:20160612213648j:plain

もずく寿司。すごいつるつるで麺のよう。 f:id:Nilfs:20160612213919j:plain

千歳ちゃん。一頭一頭名前をつけて出荷しているこだわりの強い牧場の牛を一頭買いして寿司にしているらしい。 f:id:Nilfs:20160612214107j:plain

かんぴょう巻きと、納豆巻き。すごいスペックの海苔で巻かれた寿司。海苔の世界でトップクラスとのこと。 f:id:Nilfs:20160612214555j:plain

穴子が2巻出ました。塩ゆず、山椒の葉。どちらも美味でした。今日一の予感! f:id:Nilfs:20160612215100j:plain

デザートにどら焼きと、羊羹をいただきました。(どこのやつだったか説明してもらったけど覚えてない・・・) f:id:Nilfs:20160612183136j:plain

f:id:Nilfs:20160612183128j:plain

料理もお皿も、かかっている絵も何でも知ってるすごい店員さんだったな。

飯田橋を散歩しながら二軒目を見つけたけど、また今度まとめよう。

CollectionViewを使おうと思ってSwiftでCocoaBindingを使ってみた

XCode Version 7.1.1 (7B1005) Swift2.1で試しました。

iOSのアプリは書いたことがあったけど、OSXのアプリは書いたことがなくて色々ハマっている。 iOSだったらUIXXってクラスを使ってGUIを構築してたけど、OSXだとNSXXってクラスを使っていくようだ。

iOSにはなかった気がするけど、CocoaBindingという機能があるらしい。かなり前からあるみたいだけど、普段はWPFでMVVMなコードを書いているのでVM的なものが簡単に実装できるのですごく便利そうだ。

Cocoa Binding : バインディングって何なのさ

ちなみにAppleのドキュメントはこちら developer.apple.com

下のリンクを参考にしながら、コピペでコードを書いてたところ少しハマったのでまとめておく qiita.com

ビルドが通らなくなる

Storyboard上でCollectionViewを追加したところ

Unknown segue relationship : Prototype

というようなエラーが出てビルドが通らなくなってしまった。

答えはこちら。 stackoverflow.com

追加したタイミングで、CollectionViewからCollectionViewItemへのsegueが登録されていた。これが犯人らしく、一度CollectionViewItemを削除して、CollectionViewItemを追加したらビルドが通った。 stackoverflowの通り手動でItemViewの関連づけをしてやる必要がある

実行時にエラーが出た

[73280:1183774] *** NSForwarding: warning: object 0x6080000454f0 of class 'Foo.Bar' does not implement methodSignatureForSelector: -- trouble ahead
Unrecognized selector -[Foo.Bar addObserver:forKeyPath:options:context:]

のようなエラーが出た。バインド元になっている自分で定義したクラスにインターフェイスがないとのこと。NSObjectを継承させることでうまくいった。

iOSと同じつもりでコードを書いてるとちょこちょこハマってしまうのが辛い・・・

AppDelegateでStoryboardからNSWindowControllerを取得してウィンドウを表示するだけでハマった

XCode Version 7.1.1 (7B1005) Swift2.1で試しました。

かなりはまってしまったが、答えはここにあった。表示したいウィンドウのNSWindowControllerをメンバ変数等で拘束しておかないと正しく動作しなかった。 stackoverflow.com

最小コードにすると以下のようにshowWindowするときにインスタンス化されたコントローラーを束縛しておかないといけない。myControllerへの代入コードを除去すると表示されなくなってしまう。

var myController:NSWindowController? = nil

func applicationDidFinishLaunching(aNotification: NSNotification) {
    let controller = mainStoryboard.instantiateInitialController() as? NSWindowController
    myController = controller
    myController?.showWindow(nil)
}

CFArrayはArrayと等価じゃなかった

XCode Version 7.1.1 (7B1005) Swift2.1で試しました。

CGWindowListCreateDescriptionFromArrayに[Int]を渡したところコンパイルが通ったのでCFArrayとArrayが等価だと思ってていたが使い方が間違っていたようなのでメモ

let windowArray = [1310]
let windowsdescription:CFArrayRef = CGWindowListCreateDescriptionFromArray(windowArray)!;
let windowInfos = windowsdescription as NSArray? as? [[String: AnyObject]]
print(windowInfos?.description)

1310のWindowがあるときに上のようなコードだと、windowInfosが空っぽになってしまう。

let windowIds = [1310]
let windowArray = CFArrayCreate ( nil, UnsafeMutablePointer<UnsafePointer<Void>>(windowIds), windowIds.count,nil)
let windowsdescription = CGWindowListCreateDescriptionFromArray(windowArray)!;
let windowInfos = windowsdescription as NSArray? as? [[String: AnyObject]]
print(windowInfos?.description)

のようにCFArrayを作ってから関数を呼ぶようにすると無事適切な値が帰ってくるようになった。 それっぽくコンパイルが通っても意図通りになっていないケースがあるのでObjectiveCの関数を呼ぶ時は注意が必要そうだ。

GraphQLのサンプルに書き加えてみた

できたこと

独自のItemというデータ構造を追加してそれを作成・取得することができるようになった。

データ定義をしておくとバリテーションをしてくれることがわかった。 クライアント側で欲しいフィールドを調整したい場合は便利そうな気がした。

独自実装を追加していく

前回起動まで成功した https://github.com/RisingStack/graphql-serverをローカルにクローンしてきてこのクライアントとサーバーをいじっていきます。

Nodejs+MongoDBという環境で実装されていて、今回は

  1. mongoose(MongoDBライブラリ)のモデルクラスの定義
  2. GraphQLのスキーマを定義
  3. クライアント側コードを記述。作成と取得クエリを投げるようにする

という手順で作業を進めます。

mongoose(MongoDBライブラリ)のモデルクラスの定義

src/server/user.jsがmongooseのモデルクラスの定義なので、これをコピペしてsrc/server/item.jsを作ります。以下のようなコードになりました。

import mongoose from 'mongoose';

var ItemSchema = new mongoose.Schema({
  name: {
    type: String
  }
});

var Item = mongoose.model('Item', ItemSchema);

export default Item;
GraphQLのスキーマを定義

src/server/schema.jsを編集していきます。

import Item from './item';

を追加して先ほど書いたitem.jsを読み込みます。

GraphQLスキーマ向けにモデル定義をします。mongooseの方でもしてるので一緒にできると良いなと思います。

var itemType = new GraphQLObjectType({
  name: 'Item',
  description: 'Item creator',
  fields: () => ({
    id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'The id of the item.',
    },
    name: {
      type: GraphQLString,
      description: 'The name of the item.',
    },
  })
});

GraphQLSchemaのqueryには取得クエリ、mutationには作成・更新・削除などの変更を加えるクエリを実装します。 詳しくは仕様を読むと良いです。

取得クエリ(getItem)を定義

  query: new GraphQLObjectType({
    name: 'RootQueryType',
    fields: {
      getItem: {
        type: itemType,
        args: {
          name: {
            name: 'name',
            type: new GraphQLNonNull(GraphQLString)
          }
        },
        resolve: (root, {name}, source, fieldASTs) => {
          return Item.findOne({name: name});
        }
      },
    }
  }

次に作成クエリ(createItem)を定義します。

  mutation: new GraphQLObjectType({
    name: 'Mutation',
    fields: {
      createItem: {
        type: itemType,
        args: {
          name: {
            name: 'name',
            type: GraphQLString
          }
        },
        resolve: (obj, {name}, source, fieldASTs) => co(function *() {
          var item = new Item();
          item.name = name;

          return yield item.save();
        })
      },
    }
  }),

最終的にsrc/server/schema.jsは以下のようになりました。

import {
  GraphQLObjectType,
  GraphQLNonNull,
  GraphQLSchema,
  GraphQLString,
  GraphQLList
} from 'graphql/type';

import co from 'co';
import User from './user';
import Item from './item';

/**
 * generate projection object for mongoose
 * @param  {Object} fieldASTs
 * @return {Project}
 */
function getProjection (fieldASTs) {
  return fieldASTs.selectionSet.selections.reduce((projections, selection) => {
    projections[selection.name.value] = 1;

    return projections;
  }, {});
}

var userType = new GraphQLObjectType({
  name: 'User',
  description: 'User creator',
  fields: () => ({
    id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'The id of the user.',
    },
    name: {
      type: GraphQLString,
      description: 'The name of the user.',
    },
    friends: {
      type: new GraphQLList(userType),
      description: 'The friends of the user, or an empty list if they have none.',
      resolve: (user, params, source, fieldASTs) => {
        var projections = getProjection(fieldASTs);
        return User.find({
          _id: {
            // to make it easily testable
            $in: user.friends.map((id) => id.toString())
          }
        }, projections);
      },
    }
  })
});

var itemType = new GraphQLObjectType({
  name: 'Item',
  description: 'Item creator',
  fields: () => ({
    id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'The id of the item.',
    },
    name: {
      type: GraphQLString,
      description: 'The name of the item.',
    },
  })
});

var schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'RootQueryType',
    fields: {
      hello: {
        type: GraphQLString,
        resolve: function() {
          return 'world';
        }
      },
      user: {
        type: userType,
        args: {
          id: {
            name: 'id',
            type: new GraphQLNonNull(GraphQLString)
          }
        },
        resolve: (root, {id}, source, fieldASTs) => {
          var projections = getProjection(fieldASTs);
          return User.findById(id, projections);
        }
      },

      getItem: {
        type: itemType,
        args: {
          name: {
            name: 'name',
            type: new GraphQLNonNull(GraphQLString)
          }
        },
        resolve: (root, {name}, source, fieldASTs) => {
          return Item.findOne({name: name});
        }
      },
   }
  }),

  // mutation
  mutation: new GraphQLObjectType({
    name: 'Mutation',
    fields: {
      createUser: {
        type: userType,
        args: {
          name: {
            name: 'name',
            type: GraphQLString
          }
        },
        resolve: (obj, {name}, source, fieldASTs) => co(function *() {
          var projections = getProjection(fieldASTs);

          var user = new User();
          user.name = name;


          return yield user.save();
        })
      },
      deleteUser: {
        type: userType,
        args: {
          id: {
            name: 'id',
            type: new GraphQLNonNull(GraphQLString)
          }
        },
        resolve: (obj, {id}, source, fieldASTs) => co(function *() {
          var projections = getProjection(fieldASTs);
          console.log(id);
          return yield User.findOneAndRemove({_id: id});
        })
      },
      updateUser: {
        type: userType,
        args: {
          id: {
            name: 'id',
            type: new GraphQLNonNull(GraphQLString)
          },
          name: {
            name: 'name',
            type: GraphQLString
          }
        },
        resolve: (obj, {id, name}, source, fieldASTs) => co(function *() {
          var projections = getProjection(fieldASTs);

          yield User.update({
            _id: id
          }, {
            $set: {
              name: name
            }
          });

          return yield User.findById(id, projections);
        })
      },

      createItem: {
        type: itemType,
        args: {
          name: {
            name: 'name',
            type: GraphQLString
          }
        },
        resolve: (obj, {name}, source, fieldASTs) => co(function *() {
          var projections = getProjection(fieldASTs);

          var item = new Item();
          item.name = name;

          return yield item.save();
        })
      },
    }
  }),
});

export var getProjection;
export default schema;
クライアント側コードを記述。作成と取得クエリを投げるようにする

作成クエリを投げるコードを書くのでsrc/client/mutation.jsを編集します。

Itemデータを作成するために先ほど実装したcreateItemを使います。hogehogehogeというItemを作成します。

var itemName = 'hogehogehoge'

request
  .post('http://localhost:3000/data')
  .send({
    query: `
    mutation M($name: String!) {
      createItem(name: $name) {
        name
      }
    }
    `,
    params: {
      name: itemName
    }
  })
  .end(function (err, res) {
    debug(err || res.body);
    debug('created', res.body);
  });

src/client/mutation.jsは以下のようになりました。最初からあったコードはデバッグの都合で除去しました。

import request from 'superagent';
import Debug from 'debug';

var debug = new Debug('client:mutation');
var itemName = 'hogehogehoge'

request
  .post('http://localhost:3000/data')
  .send({
    query: `
    mutation M($name: String!) {
      createItem(name: $name) {
        name
      }
    }
    `,
    params: {
      name: itemName
    }
  })
  .end(function (err, res) {
    debug(err || res.body);
    debug('created', res.body);
  });

取得クエリを投げるコードを書きます。src/client/query.jsを以下のようなコードを追加します。 (var name = 'hogehogehoge'としていたらうまく動かなかったです。変数名とフィールド名がぶつかるとまずい?)

var itemName = 'hogehogehoge'
request
  .get('http://localhost:3000/data')
  .query({
    query: `{
      getItem(name: "${itemName}") {
        name
      }
    }`
  })
  .end(function (err, res) {
    debug('items', res.body);
  });

ということで、src/client/query.jsは以下のようになりました。最初からあったコードはデバッグの都合で除去しました。

import request from 'superagent';
import Debug from 'debug';

var debug = new Debug('client:query');
var itemName = 'hogehogehoge'

request
  .get('http://localhost:3000/data')
  .query({
    query: `{
      getItem(name: "${itemName}") {
        name
      }
    }`
  })
  .end(function (err, res) {
    debug('items', res.body);
  });

上記のようにコードを編集していったら、前回同様に

npm start

としてサーバーを起動して、別のscreenで

npm run client

とクライアントを起動すると、無事データの作成と取得が確認できます。

GraphQLサーバー起動まで試した

Facebookの発表したGraphQLが気になったのでインストールまでやってみました。

qiitaではまだ記事が全然上がっていない模様。

GraphQLに関する1件の投稿 - Qiita

ここにすでにサーバーの実装がいたので試すのは簡単そう。

RisingStack/graphql-server · GitHub

インストールの説明に手順が書いてあるので問題ないのですが以下のような手順でやりました。 環境はUbuntu 14.04です。

sudo apt-get install mongodb
git clone https://github.com/RisingStack/graphql-server.git ~/graphql-server
cd ~/graphql-server
npm install
npm run seed
npm start

これでサーバーが起動します。mongodbが起動していないと、"npm run seed"のところで

Error: connect ECONNREFUSED
    at exports._errnoException (util.js:746:11)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1010:19)

こんなエラーが出てしまうので注意。

無事サーバーが起動したところで、別のコンソールで

npm run client

とクライアントを起動すると何か出力が出て起動を確認できました。めでたしめでたし

次はもう少し弄ってみる予定。