Jenkinsメモ
github, jenkins, aws
git
submodule
- Reference
- Git submodule の基礎
- git submoduleを今風な感じで削除する
jenkins
plugin
- Reference
- How to install a plugin in Jenkins manually?
- MSBuild Plugin
- After installation, there is setting form in "Global Tool Configuration".
job
- Reference
- Hudson/JenkinsでVisual Studioプロジェクトのビルドをする
- JenkinsとMSBuild PluginでVisual Studioのプロジェクトをビルドしてみたよ
- example
- MSBuild sample.sln /t:Build /p:VisualStudioVersion=14;Configuration=Debug;Platform=x86
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; }