Object subclass: #Kvs instanceVariableNames: 'dict log' classVariableNames: '' poolDictionaries: '' category: 'TDDBC-Tokyo16'! !Kvs methodsFor: 'initialization' stamp: 'sumim 8/7/2011 22:23'! initialize dict := Dictionary new. log := Dictionary new! ! !Kvs methodsFor: 'accessing' stamp: 'sumim 8/7/2011 22:41'! at: key key ifNil: [self error: 'キーにnilは使用できない']. ^dict at: key!]lang[(34 3 3 7 18)0,5,0,5,0! ! !Kvs methodsFor: 'accessing' stamp: 'sumim 8/8/2011 09:20'! at: key put: value | time | time := DateAndTime now. key ifNil: [self error: 'キーにnilは使用できない']. self removeKeyFromLog: key. (log at: time ifAbsentPut: [OrderedCollection new]) add: key. ^dict at: key put: value!]lang[(81 3 3 7 121)0,5,0,5,0! ! !Kvs methodsFor: 'accessing' stamp: 'sumim 8/7/2011 23:52'! dump | sortedKeys | sortedKeys := (log keys sort collect: [:time | log at: time]) concatenation reversed. ^sortedKeys collect: [:key| key -> (self at: key)]! ! !Kvs methodsFor: 'accessing' stamp: 'sumim 8/8/2011 09:21'! dumpAfter: period | sortedTimes found | sortedTimes := log keys sort. found := sortedTimes findLast: [:time | time < period]. found = 0 ifTrue: [^#() copy]. ^((sortedTimes allButFirst: found) collect: [:time | log at: time]) concatenation collect: [:key | dict associationAt: key]! ! !Kvs methodsFor: 'accessing' stamp: 'sumim 8/8/2011 11:02'! removeAllBeforeAgo: duration | period sortedTimes index | period := DateAndTime now - duration. sortedTimes := log keys sort. index := sortedTimes findLast: [:time | time < period]. index = 0 ifTrue: [^self]. ^((sortedTimes first: index) collect: [:time | log at: time]) concatenation collect: [:key | self removeKey: key]! ! !Kvs methodsFor: 'accessing' stamp: 'sumim 8/7/2011 23:05'! removeKey: key key ifNil: [self error: 'キーにnilは使用できない']. self removeKeyFromLog: key. ^dict removeKey: key ifAbsent: []!]lang[(41 3 3 7 67)0,5,0,5,0! ! !Kvs methodsFor: 'adding' stamp: 'sumim 8/8/2011 00:45'! addAll: assocs | time | time := DateAndTime now. (assocs anySatisfy: [:assoc | assoc key isNil]) ifTrue: [self error: 'キーにnilは使用できない']. assocs do: [:assoc | self at: assoc key put: assoc value time: time]!]lang[(122 3 3 7 73)0,5,0,5,0! ! !Kvs methodsFor: 'private' stamp: 'sumim 8/8/2011 09:20'! at: key put: value time: time key ifNil: [self error: 'キーにnilは使用できない']. self removeKeyFromLog: key. (log at: time ifAbsentPut: [OrderedCollection new]) add: key. ^dict at: key put: value!]lang[(56 3 3 7 121)0,5,0,5,0! ! !Kvs methodsFor: 'private' stamp: 'sumim 8/7/2011 23:13'! removeKeyFromLog: key (log associations detect: [:assoc | assoc value includes: key] ifNone: []) ifNotNilDo: [:assoc | (assoc value remove: key; yourself) ifEmpty: [log removeKey: assoc key]].! ! !Kvs methodsFor: 'obsolete' stamp: 'sumim 8/7/2011 22:53'! addAll: assocs time: time (assocs anySatisfy: [:assoc | assoc key isNil]) ifTrue: [self error: 'キーにnilは使用できない']. assocs do: [:assoc | self at: assoc key put: assoc value time: time]!]lang[(97 3 3 7 73)0,5,0,5,0! ! TestCase subclass: #KvsTest instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TDDBC-Tokyo16'! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/7/2011 23:45'! test01xキーと値を追加して値を取り出せる "仕様変更につき削除" [ | kvs key val | kvs := Kvs new. key := #key. val := 'val'. kvs at: key put: val. self assert: (kvs at: key) = val]!]lang[(7 16 3 9 124)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/7/2011 22:06'! test02xキー値の一覧を得られる "仕様変更につき削除" [ | kvs pairs | kvs := Kvs new. pairs := {#key1->'val1'. #key2->'val2'. #key3->'val3'}. pairs do: [:assoc | kvs at: assoc key put: assoc value]. self assert: kvs dump asSet = pairs asSet]!]lang[(7 11 3 9 194)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 01:14'! test03xキーにnilを与えると例外を発生 "仕様変更につき削除" [ | kvs | kvs := Kvs new. self should: [self shouldnt: [kvs at: nil] raise: KeyNotFound] raise: Error. self should: [kvs at: nil put: 'value'] raise: Error]!]lang[(7 3 3 10 3 9 162)0,5,0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/7/2011 23:46'! test04x値にはnilも許容する "仕様変更につき削除" [ | kvs | kvs := Kvs new. kvs at: #key put: nil. self assert: (kvs at: #key) = nil]!]lang[(7 3 3 5 3 9 89)0,5,0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/7/2011 23:46'! test05x指定したキーとその値を削除できる "仕様変更につき削除" [ | kvs | kvs := Kvs new. kvs at: #k1 put: 'v1'. kvs at: #k2 put: 'v2'. kvs removeKey: #k1. self deny: [kvs dump includes: #k1->'v2']]!]lang[(7 16 3 9 142)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/7/2011 23:47'! test06xキー値削除時にキーが存在しない場合は何もしない "仕様変更につき削除" [ | kvs pairs | kvs := Kvs new. pairs := {#k1->'v1'. #k2->'v2'}. pairs do: [:assoc | kvs at: assoc key put: assoc value]. kvs removeKey: #k3. self assert: [kvs dump asSet = pairs asSet]]!]lang[(7 23 3 9 194)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/7/2011 22:27'! test07xキー値削除時にnilを与えると例外が発生 "仕様変更につき削除" [ | kvs | kvs := Kvs new. kvs at: #k1 put: 'v1'. kvs at: #k2 put: 'v2'. self should: [kvs removeKey: nil] raise: Error]!]lang[(7 7 3 10 3 9 126)0,5,0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/7/2011 23:47'! test08xすでに存在するキーに値を設定すると上書きする "仕様変更につき削除" [ | kvs | kvs := Kvs new. kvs at: #key put: 'val1'. self assert: (kvs at: #key) = 'val1'. kvs at: #key put: 'val2'. self assert: (kvs at: #key) = 'val2']!]lang[(7 22 3 9 161)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/7/2011 23:47'! test09x複数のキーと値の組を追加できる "使用変更につき削除" [ | kvs pairs | kvs := Kvs new. pairs := {#k1->'v1'. #k2->'v2'}. kvs addAll: pairs. self assert: kvs dump asSet = pairs asSet]!]lang[(7 15 3 9 133)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 01:14'! test10x複数キー値追加時には同じキーが複数ある場合には最後に指定されたものが使用される "仕様変更につき削除" [ | kvs pairs | kvs := Kvs new. pairs := {#k1->'v1'. #k2->'v2'. #k1->'v3'}. kvs addAll: pairs. self assert: (kvs at: #k1) = 'v3']!]lang[(7 39 3 9 136)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/7/2011 23:48'! test11x複数キー値追加時には既に存在するキーがある場合も指定したものが優先される "仕様変更につき削除" [ | kvs pairs1 pairs2 | kvs := Kvs new. pairs1 := {#k1->'v1'. #k2->'v2'}. kvs addAll: pairs1. pairs2 := {#k1->'v3'. #k2->'v4'}. kvs addAll: pairs2. self assert: kvs dump asSet = pairs2 asSet]!]lang[(7 36 3 9 200)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/7/2011 22:43'! test13xキー値追加時に時刻も渡せるように仕様変更!]lang[(7 20)0,5! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:50'! test14xキーと値と時刻を追加して値を取り出せる "仕様変更につき削除" [ | kvs key val | kvs := Kvs new. key := #key. val := 'val'. kvs at: key put: val time: DateAndTime now. self assert: (kvs at: key) = val]!]lang[(7 19 3 9 146)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:49'! test15xキー値の新しく追加された順に列んだ一覧を得られる "仕様変更につき削除" [ | kvs pairs now | kvs := Kvs new. now := DateAndTime now. pairs := {#key1->'val1'. #key2->'val2'. #key3->'val3'}. pairs do: [:assoc | kvs at: assoc key put: assoc value time: (now := now + 1 seconds)]. self assert: kvs dump = pairs reversed]!]lang[(7 24 3 9 251)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:49'! test16xキーにnilを与えると例外を発生 "仕様変更につき削除" [ | kvs | kvs := Kvs new. self should: [self shouldnt: [kvs at: nil] raise: KeyNotFound] raise: Error. self should: [kvs at: nil put: 'value' time: DateAndTime now] raise: Error]!]lang[(7 3 3 10 3 9 184)0,5,0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:50'! test17x値にはnilも許容する "仕様変更につき削除" [ | kvs | kvs := Kvs new. kvs at: #key put: nil time: DateAndTime now. self assert: (kvs at: #key) = nil]!]lang[(7 3 3 5 3 9 111)0,5,0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:50'! test18x指定したキーとその値を削除できる "仕様変更につき削除" [ | kvs | kvs := Kvs new. kvs at: #k1 put: 'v1' time: DateAndTime now. kvs at: #k2 put: 'v2' time: DateAndTime now. kvs removeKey: #k1. self deny: [kvs dump includes: #k1->'v2']]!]lang[(7 16 3 9 186)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:50'! test19xキー値削除時にキーが存在しない場合は何もしない "仕様変更につき削除" [ | kvs pairs | kvs := Kvs new. pairs := {#k1->'v1'. #k2->'v2'}. pairs do: [:assoc | kvs at: assoc key put: assoc value time: DateAndTime now]. kvs removeKey: #k3. self assert: [kvs dump asSet = pairs asSet]]!]lang[(7 23 3 9 216)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:50'! test20xキー値削除時にnilを与えると例外が発生 "仕様変更につき削除" [ | kvs | kvs := Kvs new. kvs at: #k1 put: 'v1' time: DateAndTime now. kvs at: #k2 put: 'v2' time: DateAndTime now. self should: [kvs removeKey: nil] raise: Error]!]lang[(7 7 3 10 3 9 170)0,5,0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:50'! test21xすでに存在するキーに値を設定すると上書きする "仕様変更につき削除" [ | kvs | kvs := Kvs new. kvs at: #key put: 'val1' time: DateAndTime now. self assert: (kvs at: #key) = 'val1'. kvs at: #key put: 'val2' time: DateAndTime now. self assert: (kvs at: #key) = 'val2']!]lang[(7 22 3 9 205)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:46'! test22x複数のキーと値の組を追加できる "使用変更につき削除" [ | kvs assocs | kvs := Kvs new. assocs := {#k1->'v1'. #k2->'v2'}. kvs addAll: assocs time: DateAndTime now. self assert: kvs dump = assocs reversed]!]lang[(7 15 3 9 156)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:39'! test23x複数キー値追加時には同じキーが複数ある場合には最後に指定されたものが使用される "仕様変更につき削除" [ | kvs assocs | kvs := Kvs new. assocs := {#k1->'v1'. #k2->'v2'. #k1->'v3'}. kvs addAll: assocs time: DateAndTime now. self assert: (kvs at: #k1) = 'v3']!]lang[(7 39 3 9 161)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:39'! test24x複数キー値追加時には既に存在するキーがある場合も指定したものが優先される "仕様変更につき削除" [ | kvs now assocs1 assocs2 | kvs := Kvs new. now := DateAndTime now. assocs1 := {#k1->'v1'. #k2->'v2'}. kvs addAll: assocs1 time: now. assocs2 := {#k1->'v3'. #k2->'v4'}. kvs addAll: assocs2 time: now. self assert: kvs dump = {#k2->'v4'. #k1->'v3'}]!]lang[(7 36 3 9 259)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 01:14'! test25x複数キー値追加時には既に存在するキーがある場合も指定したものが優先される "仕様変更につき削除" [ | kvs now assocs1 assocs2 | kvs := Kvs new. now := DateAndTime now. assocs1 := {#k1->'v1'. #k2->'v2'}. kvs addAll: assocs1 time: now. assocs2 := {#k1->'v3'. #k2->'v4'}. kvs addAll: assocs2 time: now. self assert: kvs dump = {#k2->'v4'. #k1->'v3'}]!]lang[(7 36 3 9 259)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:49'! test26x指定した時刻以降のキー値一覧が得られる "仕様変更につき削除" [ | kvs pairs now | kvs := Kvs new. now := DateAndTime now. pairs := {#key1->'val1'. #key2->'val2'. #key3->'val3'}. pairs doWithIndex: [:assoc :delta | kvs at: assoc key put: assoc value time: (now + delta seconds)]. self assert: (kvs dumpAfter: now + 2 seconds) = pairs allButFirst]!]lang[(7 19 3 9 291)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:50'! test27x現時刻から指定した時間の長さより前の時点より前に登録されたデータを一括削除できる "仕様変更につき削除" [ | kvs pairs time | kvs := Kvs new. time := DateAndTime now - 2 minutes. pairs := {#key1->'val1'. #key2->'val2'. #key3->'val3'}. pairs doWithIndex: [:assoc :delta | kvs at: assoc key put: assoc value time: (time + (delta * 30) seconds)]. self assert: (kvs removeAllBeforeAgo: 90 seconds; dump) = pairs allButFirst reversed]!]lang[(7 40 3 9 332)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:35'! test28xキー値追加時刻に時刻の指定はせずに現時刻を使用する仕様変更!]lang[(7 29)0,5! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:46'! test29x複数のキーと値の組を追加できる | kvs assocs | kvs := Kvs new. assocs := {#k1->'v1'. #k2->'v2'}. kvs addAll: assocs. self assert: kvs dump = assocs reversed!]lang[(7 15 130)0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:43'! test30x複数キー値追加時には同じキーが複数ある場合には最後に指定されたものが使用される | kvs assocs | kvs := Kvs new. assocs := {#k1->'v1'. #k2->'v2'. #k1->'v3'}. kvs addAll: assocs. self assert: (kvs at: #k1) = 'v3'!]lang[(7 39 135)0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:43'! test31x複数キー値追加時には既に存在するキーがある場合も指定したものが優先される | kvs assocs1 assocs2 | kvs := Kvs new. assocs1 := {#k1->'v1'. #k2->'v2'}. kvs addAll: assocs1. assocs2 := {#k1->'v3'. #k2->'v4'}. kvs addAll: assocs2. self assert: kvs dump = {#k2->'v4'. #k1->'v3'}!]lang[(7 36 206)0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:45'! test32x複数キー値追加時には既に存在するキーがある場合も指定したものが優先される | kvs assocs1 assocs2 | kvs := Kvs new. assocs1 := {#k1->'v1'. #k2->'v2'}. kvs addAll: assocs1. assocs2 := {#k1->'v3'. #k2->'v4'}. kvs addAll: assocs2. self assert: kvs dump = {#k2->'v4'. #k1->'v3'}!]lang[(7 36 206)0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:53'! test33xキーと値と時刻を追加して値を取り出せる | kvs key val | kvs := Kvs new. key := #key. val := 'val'. kvs at: key put: val. self assert: (kvs at: key) = val!]lang[(7 19 120)0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:54'! test34xキー値の新しく追加された順に列んだ一覧を得られる | kvs pairs | kvs := Kvs new. pairs := {#key1->'val1'. #key2->'val2'. #key3->'val3'}. pairs do: [:assoc | kvs at: assoc key put: assoc value. 1 seconds asDelay wait]. self assert: kvs dump = pairs reversed!]lang[(7 24 211)0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:55'! test35xキーにnilを与えると例外を発生 | kvs | kvs := Kvs new. self should: [self shouldnt: [kvs at: nil] raise: KeyNotFound] raise: Error. self should: [kvs at: nil put: 'value'] raise: Error!]lang[(7 3 3 10 158)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:56'! test36x値にはnilも許容する | kvs | kvs := Kvs new. kvs at: #key put: nil. self assert: (kvs at: #key) = nil!]lang[(7 3 3 5 85)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:56'! test37x指定したキーとその値を削除できる | kvs | kvs := Kvs new. kvs at: #k1 put: 'v1'. kvs at: #k2 put: 'v2'. kvs removeKey: #k1. self deny: [kvs dump includes: #k1->'v2']!]lang[(7 16 138)0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:57'! test38xキー値削除時にキーが存在しない場合は何もしない | kvs pairs | kvs := Kvs new. pairs := {#k1->'v1'. #k2->'v2'}. pairs do: [:assoc | kvs at: assoc key put: assoc value]. kvs removeKey: #k3. self assert: [kvs dump asSet = pairs asSet]!]lang[(7 23 190)0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:57'! test39xキー値削除時にnilを与えると例外が発生 | kvs | kvs := Kvs new. kvs at: #k1 put: 'v1'. kvs at: #k2 put: 'v2'. self should: [kvs removeKey: nil] raise: Error!]lang[(7 7 3 10 122)0,5,0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 00:58'! test40xすでに存在するキーに値を設定すると上書きする | kvs | kvs := Kvs new. kvs at: #key put: 'val1'. self assert: (kvs at: #key) = 'val1'. kvs at: #key put: 'val2'. self assert: (kvs at: #key) = 'val2'!]lang[(7 22 157)0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 01:01'! test41x指定した時刻以降のキー値一覧が得られる | kvs pairs | kvs := Kvs new. pairs := {#key1->'val1'. #key2->'val2'. #key3->'val3'}. pairs do: [:assoc | kvs at: assoc key put: assoc value. 1 seconds asDelay wait]. self assert: (kvs dumpAfter: DateAndTime now - 2.5 seconds) = pairs allButFirst!]lang[(7 19 252)0,5,0! ! !KvsTest methodsFor: 'tests' stamp: 'sumim 8/8/2011 01:02'! test42x現時刻から指定した時間の長さより前の時点より前に登録されたデータを一括削除できる | kvs pairs | kvs := Kvs new. pairs := {#key1->'val1'. #key2->'val2'. #key3->'val3'}. pairs do: [:assoc | kvs at: assoc key put: assoc value. 1 seconds asDelay wait]. self assert: (kvs removeAllBeforeAgo: 2.5 seconds; dump) = pairs allButFirst reversed!]lang[(7 40 258)0,5,0! !