読者です 読者をやめる 読者になる 読者になる

Jenkinsメモ

github, jenkins, aws

git

submodule

jenkins

plugin

job

with google test

job flow

使い方のメモ。

githubからコードを入手
https://github.com/Excel-DNA

ExcelDna\Sourceにあるソリューションを開いてでビルドする。
ExcelDna\Build\build.batを実行。

新しいC#プロジェクトを作成。
ExcelDna\DistributionにあるExcelDna.Integrationを参照に追加。

namespace Excel
{
    public class Export
    {
        public static double Add(double x, double y) {
            return x + y;
        }
    }
}


ExcelDna.dnaを編集

<DnaLibrary RuntimeVersion="v4.0">
	<ExternalLibrary Path="Excel.dll" />
</DnaLibrary>


ExcelDna.xllを開いて、新しいbookを作成し、Addを呼んでみる。
動いた!


Rangeを返す。

public static object[] ReturnArray(int n)
{
    object[] array = new object[n];
    for (int i = 0; i < n; ++i) {
        array[i] = i;
    }
    return array;
}

public static object[,] ReturnMatrix(int n)
{
    object[,] array = new object[n, n];
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < n; ++j)
        {
            array[i, j] = i + j;
        }
    }
    return array;
}


Rangeを受け取る

public static string UpdateRange(object[,] range)
{
    for (int i = 0; i < range.GetLength(0); ++i)
    {
        for (int j = 0; j < range.GetLength(1); ++j)
        {
            range[i, j] = i + j;
        }
    }
    return "success!!";
}

ん?? 更新できない・・・

できないことはないようだが、推奨されていないみたい。
https://groups.google.com/forum/#!topic/exceldna/SCPBnuw7Cl8

tupleを展開して、関数の引数にする。

したいこと。

int main()
{
    auto x = std::make_tuple(1, 2.0, "three");
    auto f = [](auto a, auto b, auto c) {
        std::cout << typeid(a).name() << std::endl;
        std::cout << typeid(b).name() << std::endl;
        std::cout << typeid(c).name() << std::endl;
    };
    apply(f, x);

    return 0;
}

上記のようにapplyに関数とtupleを渡した時に、下記のように関数を評価したい。

f(1, 2.0, "three");

variadic templateを再帰的に呼び出すことによって、tupleの中身を順次Args&... argsに貯める。最後に関数fに渡す。

template <int N>
struct Expand {
    template <typename F, typename Tuple, typename... Args>
    static void apply(F& f, Tuple& t, Args&... args)
    {
        Expand<N - 1>::apply(f, t, std::get<N - 1>(t), args...);
    }
};

template <>
struct Expand<0> {
    template <typename F, typename Tuple, typename... Args>
    static void apply(F& f, Tuple& t, Args&... args)
    {
        f(args...);
    }
};

template <typename F, typename Tuple>
void apply(F& f, Tuple& t)
{
    Expand<std::tuple_size<Tuple>::value>::apply(f, t);
}


実行イメージ
Expand<3>::apply(f, x)
Expand<2>::apply(f, x, "three")
Expand<1>::apply(f, x, 2.0, "three")
Expand<0>::apply(f, x, 1, 2.0, "three")
f(1, 2.0, "three")

C++でC#のクエリのようなものを作る。

最近、C#を勉強していてlinqのクエリ(?)がすごく便利だと感じたので、C++でそれっぽいのを作ろう。
進捗は

  • select
  • select_with_index
  • select_unzip
  • where
  • where_with_index
  • skip
  • take
  • zip

を作成。

使い方は下記の通り。
コードは
GitHub - nishiba/query: c++ code like c# query

int main()
{
    std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7 };
    std::vector<int> y = { 0, 1, 2, 3, 4, 5, 6, 7 };
    for (auto& x : where(v, [](int x) -> bool {return (x % 2) == 0; })) {
        std::cout << x << std::endl;
    }

    std::cout << std::endl;
    for (auto& x : where_with_index(v, [](int x, std::size_t index) -> bool {return (index < 4); })) {
        std::cout << x << std::endl;
    }

    std::cout << std::endl;
    for (auto& x : skip(v, 1).where([](int x) {return x < 6; })) {
        std::cout << x << std::endl;
    }

    std::cout << std::endl;
    for (auto x : skip(v, 1).select([](int x) {return x < 6; })) {
        std::cout << x << std::endl;
    }

    std::cout << std::endl;
    for (auto& x : zip(v, y).take(2)) {
        std::cout << x.get<0>() << "," << x.get<1>() << std::endl;
    }

    std::cout << std::endl;
    for (auto&& x : select_unzip(zip(v, y), [](auto& x, auto& y) {return x + y; })) {
        std::cout << x << std::endl;
    }

    std::cout << std::endl;
    for (auto& x : skip(v, 1).take(3)) {
        std::cout << x << std::endl;
    }

    return 0;
}

C#からExcelを開く

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Office.Interop;

using Excel = Microsoft.Office.Interop.Excel;
using System.IO;
using System.Runtime.InteropServices;

namespace excel_starter
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var app = new Excel.Application();
                // Make the object visible.
                app.Visible = true;

                // Load My Addin 
                //app.RegisterXLL(Directory.GetCurrentDirectory() + "\\addin.xll");

                // Open My Workbook 
                Excel.Workbooks wbks = app.Workbooks;
                wbks.Open(Directory.GetCurrentDirectory() + "\\addin1.xlam");
                Excel.Workbook wbk = wbks.Open(Directory.GetCurrentDirectory() + "\\example.xlsx");

                // Release COM-Objects
                Marshal.ReleaseComObject(wbk);
                Marshal.ReleaseComObject(wbks);
                Marshal.ReleaseComObject(app);
            }
            catch (Exception e) {
                Console.WriteLine(e.Message);
            }
        }
    }
}

Factory&Builderパターン再考

インスタンスの生成方法について再考。


したいこと

  • Dataの商品IDに応じて、違うルールでShelfを作りたい。
  • 新しい商品を追加も容易にしたい。追加や変更するクラス、箇所を極力小さくしたい。
int main()
{
    ProductId("c1").procedure<Screw1Builder, BoardBuilder, ShelfBuilder>();
    ProductId("c2").procedure<Screw2Builder, BoardBuilder, ShelfBuilder>();

    Shelf s1 = ShelfFactory::create(Data("c1"));
    Shelf s2 = ShelfFactory::create(Data("c2"));

    return 0;
}

上記では、IDによって違うScrewを使うように実行時にfactoryに登録している。
procedureは可変長引数となっており、手順を増やすことも容易。

ShelfFactoryはstd::functionを保持しているので、Screw1Builderなどに依存していない。
Screw1Builder等も同じBaseを継承する必要もない。

class Screw {};
class Board {};
class Shelf {};

struct WoreHouse {
    Screw screw;
    Board bord;
    Shelf shelf;
};


class ShelfFactory {
public:
    class ProcedureCreator {
        friend ShelfFactory;
    public:
        ProcedureCreator& next(const std::function<void(ShelfFactory&)>& f)
        {
            _p.push_back(f);
            return *this;
        }
    private:
        ProcedureCreator(std::list<std::function<void(ShelfFactory&)>>& p)
            : _p(p)
        {}
        std::list<std::function<void(ShelfFactory&)>>& _p;
    };


    static ProcedureCreator makeProcedure(const std::string& code)
    {
        instance()._procedures[code].clear();
        return ProcedureCreator(instance()._procedures[code]);
    }
    static Shelf create(const Data& d)
    {
        ShelfFactory& f = instance();
        f._data = d;
        for (auto& p : f._procedures[f._data.id]) p(f);
        return f._worehous.shelf;

    }
    Data _data;
    WoreHouse _worehous;
    std::map<std::string, std::list<std::function<void(ShelfFactory&)>>> _procedures;
private:
    static ShelfFactory& instance() {
        static ShelfFactory _f;
        return _f;
    }
    ShelfFactory() {}
    ShelfFactory(const ShelfFactory&) = default;
    ShelfFactory& operator =(const ShelfFactory&) = default;
};

class Screw1Builder {
public:
    void operator()(ShelfFactory& f)
    {
        std::cout << "Screw1Builder" << std::endl;
        f._worehous.screw = Screw();
    }
};

class Screw2Builder {
public:
    void operator()(ShelfFactory& f)
    {
        std::cout << "Screw2Builder" << std::endl;
        f._worehous.screw = Screw();
    }
};

class BoardBuilder {
public:
    void operator()(ShelfFactory& f)
    {
        std::cout << "BoardBuilder" << std::endl;
        f._worehous.bord = Board();
    }
};

class ShelfBuilder {
public:
    void operator()(ShelfFactory& f)
    {
        std::cout << "ShelfBuilder" << std::endl;
        f._worehous.shelf = Shelf();
    }
};


template <typename...>
struct ProcedureMaker {
    static void apply(ShelfFactory::ProcedureCreator& p) {
    }
};

template <typename T, typename... Args>
struct ProcedureMaker<T, Args...> {
    static void apply(ShelfFactory::ProcedureCreator& p) {
        p.next(T());
        ProcedureMaker<Args...>::apply(p);
    }
};

class ProductId {
public:
    ProductId(std::string id) : _id(id) {}
    template <typename ... Args>
    void procedure() const
    {
        ProcedureMaker<Args...>::apply(ShelfFactory::makeProcedure(_id));
    }
private:
    std::string _id;
};


新しい工程を増やす場合、新しい部品(Glass)とその作り方(GlassBuilder)を新たに作成。
WoreHouseに新しい部品のメンバ変数を追加。
あとはmainで製造手順を追加すればよい。

変更箇所の影響がかなり限定的にできる。

class Glass {};

struct WoreHouse {
    Screw screw;
    Board bord;
    Shelf shelf;
    Glass glass; //追加
};

class GlassBuilder {
public:
    void operator()(ShelfFactory& f)
    {
        std::cout << "GlassBuilder" << std::endl;
        f._worehous.glass = Glass();
    }
};


int main()
{
    ProductId("c3").procedure<GlassBuilder, Screw2Builder, BoardBuilder, ShelfBuilder>();
    Shelf s3 = ShelfFactory::create(Data("c3"));

    return 0;
}

Decolator, Mix-Inのような継承関係

Decolatorパターンの場合、内部で持っているコンポーネントの振る舞いが分かりにくい。Mix-Inの場合、プロパティとなるClassがtemplate classとなってしまって、複雑になる。

そこで、状況によってはあ下記のような継承もありかな。

  • RuleBaseはルール f : double -> doubleを複数保持する。
  • RuleBase::apply(double x)は、登録された順にルールをxに適用する。
  • RuleAは、ルールx + 1.0をRuleBaseに登録する。
  • RuleBは、ルールx * 3.0をRuleBaseに登録する。
  • Cは、RuleAとRuleBを持っている。継承の順番にRuleBaseに登録する。
class RuleBase {
public:
	RuleBase()  {
	}
	virtual ~RuleBase() {}
	void addRule(const std::function<double(double)>& f)
	{
		_f.push_back(f);
	}
	double apply(double x) const 
	{ 
		for (auto& f : _f) { x = f(x); }
		return x;
	}
private:
	std::list<std::function<double(double)> > _f;
};

class RuleA : virtual RuleBase {
public:
	RuleA()
	{
		addRule([&](double x) {return rule(x); });
	}
	virtual ~RuleA() {}
private:
	double rule(double x) const { return x + 1.0; }
};

class RuleB : virtual RuleBase {
public:
	RuleB()
	{
		addRule([&](double x) {return rule(x); });
	}
	virtual ~RuleB() {}
private:
	double rule(double x) const { return x * 3.0; }
};

class C : RuleA, RuleB, virtual RuleBase
{
public:
	C() {}
	double get(double x) const { return RuleBase::apply(x); }
};

int main()
{
	C c;
	std::cout << c.get(0.5) << std::endl; // (0.5 + 1.0) * 3.0
    return 0;
}