Skip to content

Instantly share code, notes, and snippets.

@zaneli
Created July 27, 2013 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zaneli/6094975 to your computer and use it in GitHub Desktop.
Save zaneli/6094975 to your computer and use it in GitHub Desktop.
「CoffeeScript によるデザインパターン(Composite)」ブログ用
class Task
constructor: (name, getTime) ->
@getName = -> name
@getTimeRequired = -> getTime()
@parent = null
class CompositeTask extends Task
constructor: (name) ->
super(name, => @subTasks.reduce ((sum, time) -> sum + time.getTimeRequired()), 0)
@subTasks = []
addSubTask: (tasks...) ->
for task in tasks
if task?.getName? and task?.getTimeRequired?
task.parent = @
@subTasks.push task
else
console.warn task?.constructor?.name + " is not a task"
@
removeSubTask: (tasks...) ->
for task in tasks
index = @subTasks.indexOf(task)
if index >= 0
@subTasks.splice(index, 1)
task.parent = null
@
class @AddDryIngredientsTask extends Task
constructor: -> super("Add dry ingredients", -> 1.0) # 小麦粉と砂糖を加えるのに1分
class @MixTask extends Task
constructor: -> super("Mix that batter up!", -> 3.0) # 混ぜるのに3分
class @MakeBatterTask extends CompositeTask
constructor: ->
super("Make batter")
@addSubTask(new AddDryIngredientsTask(), new MixTask())
class Task
constructor: (name, getTime) ->
@getName = -> name
@getTimeRequired = -> getTime()
class @AddDryIngredientsTask extends Task
constructor: -> super("Add dry ingredients", -> 1.0) # 小麦粉と砂糖を加えるのに1分
class @MixTask extends Task
constructor: -> super("Mix that batter up!", -> 3.0) # 混ぜるのに3分
class @MakeBatterTask extends Task
constructor: ->
super("Make batter", => @subTasks.reduce ((sum, time) -> sum + time.getTimeRequired()), 0)
@subTasks = []
@addSubTask(new AddDryIngredientsTask(), new MixTask())
addSubTask: (tasks...) ->
for task in tasks
if task?.getName? and task?.getTimeRequired?
@subTasks.push task
else
console.warn task?.constructor?.name + " is not a task"
@
removeSubTask: (tasks...) ->
for task in tasks
index = @subTasks.indexOf(task)
@subTasks.splice(index, 1) if index >= 0
@
class Task
constructor: (name, getTime) ->
@getName = -> name
@getTimeRequired = -> getTime()
class CompositeTask extends Task
constructor: (name) ->
super(name, => @subTasks.reduce ((sum, time) -> sum + time.getTimeRequired()), 0)
@subTasks = []
addSubTask: (tasks...) ->
for task in tasks
if task?.getName? and task?.getTimeRequired?
@subTasks.push task
else
console.warn task?.constructor?.name + " is not a task"
@
removeSubTask: (tasks...) ->
for task in tasks
index = @subTasks.indexOf(task)
@subTasks.splice(index, 1) if index >= 0
@
class @AddDryIngredientsTask extends Task
constructor: -> super("Add dry ingredients", -> 1.0) # 小麦粉と砂糖を加えるのに1分
class @MixTask extends Task
constructor: -> super("Mix that batter up!", -> 3.0) # 混ぜるのに3分
class @MakeBatterTask extends CompositeTask
constructor: ->
super("Make batter")
@addSubTask(new AddDryIngredientsTask(), new MixTask())
class Task
constructor: (name, getTime) ->
@getName = -> name
@getTimeRequired = -> getTime()
class CompositeTask extends Array
constructor: (name) ->
@getName = -> name
@getTimeRequired = -> @reduce ((sum, time) -> sum + time.getTimeRequired()), 0
class @AddDryIngredientsTask extends Task
constructor: -> super("Add dry ingredients", -> 1.0) # 小麦粉と砂糖を加えるのに1分
class @MixTask extends Task
constructor: -> super("Mix that batter up!", -> 3.0) # 混ぜるのに3分
class @MakeBatterTask extends CompositeTask
constructor: ->
super("Make batter")
@push(new AddDryIngredientsTask(), new MixTask())
package views
import org.specs2.mutable.Specification
import play.api.test.TestServer
import play.api.test.Helpers.{ running, HTMLUNIT }
class CompositeSpec extends Specification {
private val testPort = 3333
"Composite" should {
"get time required" in {
running(TestServer(testPort), HTMLUNIT) { browser =>
browser.goTo(s"http://localhost:${testPort}/composite")
browser.executeScript("""
var adiTask = new AddDryIngredientsTask();
console.log(adiTask.getTimeRequired());
var mTask = new MixTask();
console.log(mTask.getTimeRequired());
var mbTask = new MakeBatterTask();
console.log(mbTask.getTimeRequired());
""")
browser.$("#__console_log").getValue must_== """1
3
4
"""
browser.$("#__console_warn").getValue must beNull
}
}
"add some tasks" in {
running(TestServer(testPort), HTMLUNIT) { browser =>
browser.goTo(s"http://localhost:${testPort}/composite")
browser.executeScript("""
var task = new MakeBatterTask();
console.log(task.getTimeRequired());
task.addSubTask(new AddDryIngredientsTask());
console.log(task.getTimeRequired());
task.addSubTask(new AddDryIngredientsTask(), new MixTask());
console.log(task.getTimeRequired());
""")
browser.$("#__console_log").getValue must_== """4
5
9
"""
browser.$("#__console_warn").getValue must beNull
}
}
"remove some tasks" in {
running(TestServer(testPort), HTMLUNIT) { browser =>
browser.goTo(s"http://localhost:${testPort}/composite")
browser.executeScript("""
var task = new MakeBatterTask();
console.log(task.getTimeRequired());
var task1 = new AddDryIngredientsTask();
var task2 = new MixTask();
var task3 = new AddDryIngredientsTask();
var task4 = new MixTask();
task.addSubTask(task1, task2, task3, task4);
console.log(task.getTimeRequired());
task.removeSubTask(task1);
console.log(task.getTimeRequired());
task.removeSubTask(task2, task3, task4);
console.log(task.getTimeRequired());
""")
browser.$("#__console_log").getValue must_== """4
12
11
4
"""
browser.$("#__console_warn").getValue must beNull
}
}
"remove notadded tasks" in {
running(TestServer(testPort), HTMLUNIT) { browser =>
browser.goTo(s"http://localhost:${testPort}/composite")
browser.executeScript("""
var task = new MakeBatterTask();
console.log(task.getTimeRequired());
var task1 = new AddDryIngredientsTask();
var task2 = new MixTask();
var task3 = new AddDryIngredientsTask();
var task4 = new MixTask();
task.removeSubTask(task1);
console.log(task.getTimeRequired());
task.removeSubTask(task2, task3, task4);
console.log(task.getTimeRequired());
""")
browser.$("#__console_log").getValue must_== """4
4
4
"""
browser.$("#__console_warn").getValue must beNull
}
}
"add invalid tasks" in {
running(TestServer(testPort), HTMLUNIT) { browser =>
browser.goTo(s"http://localhost:${testPort}/composite")
browser.executeScript("""
var task = new MakeBatterTask();
console.log(task.getTimeRequired());
task.addSubTask(1, "a", null);
console.log(task.getTimeRequired());
""")
browser.$("#__console_log").getValue must_== """4
4
"""
browser.$("#__console_warn").getValue must_== """Number is not a task
String is not a task
undefined is not a task
"""
}
}
"remove invalid tasks" in {
running(TestServer(testPort), HTMLUNIT) { browser =>
browser.goTo(s"http://localhost:${testPort}/composite")
browser.executeScript("""
var task = new MakeBatterTask();
console.log(task.getTimeRequired());
task.removeSubTask(null, 10, "あ");
console.log(task.getTimeRequired());
""")
browser.$("#__console_log").getValue must_== """4
4
"""
browser.$("#__console_warn").getValue must beNull
}
}
}
}
window.console =
log: (msg) ->
idName = "__console_log"
$("body").append "<textarea id=\"#{idName}\">" if $("##{idName}").size() is 0
$("##{idName}").val($("##{idName}").val() + "#{msg}\n")
warn: (msg) ->
idName = "__console_warn"
$("body").append "<textarea id=\"#{idName}\">" if $("##{idName}").size() is 0
$("##{idName}").val($("##{idName}").val() + "#{msg}\n")
# テストケースで配列のindexOfが使用できなかったための回避コード
# 参考: http://qiita.com/Oakbow/items/3374175d76d82792134d
unless "indexOf" of Array::
Array::indexOf = (find, i) ->
i = 0 if i is `undefined`
i += @length if i < 0
i = 0 if i < 0
n = @length
while i < n
return i if i of this and this[i] is find
i++
-1
# テストケースで配列のreduceが使用できなかったための回避コード
# 参考: http://d.hatena.ne.jp/gakuzo/20090414/1239681929
unless "reduce" of Array::
Array::reduce = (callback, init, thisObject) ->
return init if @length is 0
index = (if init isnt `undefined` then 0 else 1)
result = (if init isnt `undefined` then init else this[0])
n = @length
while index < n
result = callback.call(thisObject, result, this[index], index, this)
index++
result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment