hyperion-api 0.0.1.alpha2 → 0.0.1.alpha3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/hyperion/api.rb +18 -0
- data/lib/hyperion/memory.rb +111 -0
- data/lib/hyperion/util.rb +19 -0
- data/spec/hyperion/api_spec.rb +18 -3
- data/spec/hyperion/fake_ds.rb +41 -40
- data/spec/hyperion/memory_spec.rb +13 -0
- data/spec/hyperion/util_spec.rb +30 -0
- metadata +8 -4
- data/lib/hyperion/dev/memory.rb +0 -113
- data/spec/hyperion/dev/memory_spec.rb +0 -11
data/lib/hyperion/api.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'hyperion/query'
|
2
2
|
require 'hyperion/filter'
|
3
3
|
require 'hyperion/sort'
|
4
|
+
require 'hyperion/util'
|
4
5
|
|
5
6
|
module Hyperion
|
6
7
|
class API
|
@@ -19,6 +20,23 @@ module Hyperion
|
|
19
20
|
Thread.current[:datastore] || raise('No Datastore installed')
|
20
21
|
end
|
21
22
|
|
23
|
+
# Assigns the datastore within the given block
|
24
|
+
def with_datastore(name, opts={})
|
25
|
+
self.datastore = new_datastore(name, opts)
|
26
|
+
yield
|
27
|
+
self.datastore = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def new_datastore(name, opts={})
|
31
|
+
begin
|
32
|
+
require "hyperion/#{name}"
|
33
|
+
rescue LoadError
|
34
|
+
raise "Can't find datastore implementation: #{name}"
|
35
|
+
end
|
36
|
+
ds_klass = Hyperion.const_get(Util.class_name(name.to_s))
|
37
|
+
ds_klass.new(opts)
|
38
|
+
end
|
39
|
+
|
22
40
|
# Saves a record. Any additional parameters will get merged onto the record before it is saved.
|
23
41
|
|
24
42
|
# Hyperion::API.save({:kind => :foo})
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'hyperion/api'
|
2
|
+
|
3
|
+
module Hyperion
|
4
|
+
class Memory
|
5
|
+
|
6
|
+
def initialize(opts={})
|
7
|
+
@id_counter = 0
|
8
|
+
@store = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def save(records)
|
12
|
+
records.map do |record|
|
13
|
+
key = API.new?(record) ? generate_key : record[:key]
|
14
|
+
record[:key] = key
|
15
|
+
store[key] = record
|
16
|
+
record
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_by_key(key)
|
21
|
+
store[key]
|
22
|
+
end
|
23
|
+
|
24
|
+
def find(query)
|
25
|
+
records = store.values
|
26
|
+
records = filter_kind(query.kind, records)
|
27
|
+
records = apply_filters(query.filters, records)
|
28
|
+
records = apply_sorts(query.sorts, records)
|
29
|
+
records = apply_offset(query.offset, records)
|
30
|
+
records = apply_limit(query.limit, records)
|
31
|
+
records
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete_by_key(key)
|
35
|
+
store.delete(key)
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def delete(query)
|
40
|
+
records = find(query)
|
41
|
+
store.delete_if do |key, record|
|
42
|
+
records.include?(record)
|
43
|
+
end
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def count(query)
|
48
|
+
find(query).length
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
attr_reader :store
|
54
|
+
|
55
|
+
def filter_kind(kind, records)
|
56
|
+
records.select do |record|
|
57
|
+
record[:kind] == kind
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def apply_filters(filters, records)
|
62
|
+
records.select do |record|
|
63
|
+
filters.all? do |filter|
|
64
|
+
value = record[filter.field]
|
65
|
+
case filter.operator
|
66
|
+
when '<'; value < filter.value
|
67
|
+
when '<='; value <= filter.value
|
68
|
+
when '>'; value > filter.value
|
69
|
+
when '>='; value >= filter.value
|
70
|
+
when '='; value == filter.value
|
71
|
+
when '!='; value != filter.value
|
72
|
+
when 'contains?'; filter.value.include?(value)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def apply_sorts(sorts, records)
|
79
|
+
records.sort { |record1, record2| compare_records record1, record2, sorts }
|
80
|
+
end
|
81
|
+
|
82
|
+
def compare_records(record1, record2, sorts)
|
83
|
+
sorts.each do |sort|
|
84
|
+
result = compare_record record1, record2, sort
|
85
|
+
return result if result
|
86
|
+
end
|
87
|
+
0
|
88
|
+
end
|
89
|
+
|
90
|
+
def compare_record(record1, record2, sort)
|
91
|
+
field1, field2 = record1[sort.field], record2[sort.field]
|
92
|
+
field1 == field2 ? nil :
|
93
|
+
field1 < field2 && sort.ascending? ? -1 :
|
94
|
+
field1 > field2 && sort.descending? ? -1 : 1
|
95
|
+
end
|
96
|
+
|
97
|
+
def generate_key
|
98
|
+
@id_counter += 1
|
99
|
+
end
|
100
|
+
|
101
|
+
def apply_offset(offset, records)
|
102
|
+
return records unless offset
|
103
|
+
records.drop offset
|
104
|
+
end
|
105
|
+
|
106
|
+
def apply_limit(limit, records)
|
107
|
+
return records unless limit
|
108
|
+
records.take(limit)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Hyperion
|
2
|
+
class Util
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def camel_case(str)
|
7
|
+
str.gsub(/[_| |\-][A-Za-z]/) { |a| a[1..-1].upcase }
|
8
|
+
end
|
9
|
+
|
10
|
+
def class_name(str)
|
11
|
+
cameled = camel_case(str)
|
12
|
+
cameled[0] = cameled[0].capitalize
|
13
|
+
cameled
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/spec/hyperion/api_spec.rb
CHANGED
@@ -14,6 +14,16 @@ describe Hyperion::API do
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
context 'factory' do
|
18
|
+
it 'bombs on unknown implementations' do
|
19
|
+
expect {api.new_datastore(:unknown)}.to raise_error("Can't find datastore implementation: unknown")
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'creates a memory datastore' do
|
23
|
+
api.new_datastore(:memory).class.should == Hyperion::Memory
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
17
27
|
context 'new?' do
|
18
28
|
it 'false if a record exists' do
|
19
29
|
api.new?({:key => 1}).should be_false
|
@@ -27,9 +37,14 @@ describe Hyperion::API do
|
|
27
37
|
context 'with fake datastore' do
|
28
38
|
attr_reader :fake_ds
|
29
39
|
|
30
|
-
|
31
|
-
|
32
|
-
|
40
|
+
def fake_ds
|
41
|
+
Thread.current[:datastore]
|
42
|
+
end
|
43
|
+
|
44
|
+
around :each do |example|
|
45
|
+
api.with_datastore(:fake_ds) do
|
46
|
+
example.run
|
47
|
+
end
|
33
48
|
end
|
34
49
|
|
35
50
|
context 'save' do
|
data/spec/hyperion/fake_ds.rb
CHANGED
@@ -1,43 +1,44 @@
|
|
1
|
-
|
1
|
+
module Hyperion
|
2
|
+
class FakeDs
|
3
|
+
|
4
|
+
attr_accessor :saved_records, :queries, :key_queries, :returns
|
5
|
+
|
6
|
+
def initialize(opts={})
|
7
|
+
@saved_records = []
|
8
|
+
@returns = []
|
9
|
+
@queries = []
|
10
|
+
@key_queries = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def save(records)
|
14
|
+
@saved_records += records
|
15
|
+
returns.shift || []
|
16
|
+
end
|
17
|
+
|
18
|
+
def find_by_key(key)
|
19
|
+
@key_queries << key
|
20
|
+
returns.shift || nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def find(query)
|
24
|
+
@queries << query
|
25
|
+
returns.shift || []
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete_by_key(key)
|
29
|
+
@key_queries << key
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete(query)
|
34
|
+
@queries << query
|
35
|
+
returns.shift || nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def count(query)
|
39
|
+
@queries << query
|
40
|
+
returns.shift || 0
|
41
|
+
end
|
2
42
|
|
3
|
-
attr_accessor :saved_records, :queries, :key_queries, :returns
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
@saved_records = []
|
7
|
-
@returns = []
|
8
|
-
@queries = []
|
9
|
-
@key_queries = []
|
10
|
-
end
|
11
|
-
|
12
|
-
def save(records)
|
13
|
-
@saved_records += records
|
14
|
-
returns.shift || []
|
15
|
-
end
|
16
|
-
|
17
|
-
def find_by_key(key)
|
18
|
-
@key_queries << key
|
19
|
-
returns.shift || nil
|
20
|
-
end
|
21
|
-
|
22
|
-
def find(query)
|
23
|
-
@queries << query
|
24
|
-
returns.shift || []
|
25
43
|
end
|
26
|
-
|
27
|
-
def delete_by_key(key)
|
28
|
-
@key_queries << key
|
29
|
-
nil
|
30
|
-
end
|
31
|
-
|
32
|
-
def delete(query)
|
33
|
-
@queries << query
|
34
|
-
returns.shift || nil
|
35
|
-
end
|
36
|
-
|
37
|
-
def count(query)
|
38
|
-
@queries << query
|
39
|
-
returns.shift || 0
|
40
|
-
end
|
41
|
-
|
42
44
|
end
|
43
|
-
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'hyperion/util'
|
2
|
+
|
3
|
+
describe Hyperion::Util do
|
4
|
+
|
5
|
+
def util
|
6
|
+
Hyperion::Util
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'camel cases words' do
|
10
|
+
util.camel_case('fake_ds').should == 'fakeDs'
|
11
|
+
util.camel_case('defaultSceneName').should == 'defaultSceneName'
|
12
|
+
util.camel_case('set defaultSceneName').should == 'setDefaultSceneName'
|
13
|
+
util.camel_case('class_name').should == 'className'
|
14
|
+
util.camel_case('once_upon_a_time').should == 'onceUponATime'
|
15
|
+
util.camel_case('with spaces').should == 'withSpaces'
|
16
|
+
util.camel_case('with-dash').should == 'withDash'
|
17
|
+
util.camel_case('starting Capital').should == 'startingCapital'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'converts to class name' do
|
21
|
+
util.class_name('fake_ds').should == 'FakeDs'
|
22
|
+
util.class_name('defaultSceneName').should == 'DefaultSceneName'
|
23
|
+
util.class_name('set defaultSceneName').should == 'SetDefaultSceneName'
|
24
|
+
util.class_name('class_name').should == 'ClassName'
|
25
|
+
util.class_name('once_upon_a_time').should == 'OnceUponATime'
|
26
|
+
util.class_name('with spaces').should == 'WithSpaces'
|
27
|
+
util.class_name('with-dash').should == 'WithDash'
|
28
|
+
util.class_name('starting Capital').should == 'StartingCapital'
|
29
|
+
end
|
30
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hyperion-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1.
|
4
|
+
version: 0.0.1.alpha3
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -46,20 +46,23 @@ dependencies:
|
|
46
46
|
description: A Generic Persistence API for Ruby
|
47
47
|
email:
|
48
48
|
- myles@8thlight.com
|
49
|
+
- skim@8thlight.com
|
49
50
|
executables: []
|
50
51
|
extensions: []
|
51
52
|
extra_rdoc_files: []
|
52
53
|
files:
|
53
|
-
- lib/hyperion/dev/memory.rb
|
54
54
|
- lib/hyperion/dev/ds_spec.rb
|
55
|
+
- lib/hyperion/util.rb
|
55
56
|
- lib/hyperion/filter.rb
|
56
57
|
- lib/hyperion/api.rb
|
57
58
|
- lib/hyperion/key.rb
|
59
|
+
- lib/hyperion/memory.rb
|
58
60
|
- lib/hyperion/sort.rb
|
59
61
|
- lib/hyperion/query.rb
|
60
|
-
- spec/hyperion/
|
62
|
+
- spec/hyperion/util_spec.rb
|
61
63
|
- spec/hyperion/key_spec.rb
|
62
64
|
- spec/hyperion/shared_examples.rb
|
65
|
+
- spec/hyperion/memory_spec.rb
|
63
66
|
- spec/hyperion/api_spec.rb
|
64
67
|
- spec/hyperion/fake_ds.rb
|
65
68
|
homepage: https://github.com/mylesmegyesi/hyperion-ruby
|
@@ -88,8 +91,9 @@ signing_key:
|
|
88
91
|
specification_version: 3
|
89
92
|
summary: A Generic Persistence API for Ruby
|
90
93
|
test_files:
|
91
|
-
- spec/hyperion/
|
94
|
+
- spec/hyperion/util_spec.rb
|
92
95
|
- spec/hyperion/key_spec.rb
|
93
96
|
- spec/hyperion/shared_examples.rb
|
97
|
+
- spec/hyperion/memory_spec.rb
|
94
98
|
- spec/hyperion/api_spec.rb
|
95
99
|
- spec/hyperion/fake_ds.rb
|
data/lib/hyperion/dev/memory.rb
DELETED
@@ -1,113 +0,0 @@
|
|
1
|
-
require 'hyperion/api'
|
2
|
-
|
3
|
-
module Hyperion
|
4
|
-
module Dev
|
5
|
-
class Memory
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@id_counter = 0
|
9
|
-
@store = {}
|
10
|
-
end
|
11
|
-
|
12
|
-
def save(records)
|
13
|
-
records.map do |record|
|
14
|
-
key = API.new?(record) ? generate_key : record[:key]
|
15
|
-
record[:key] = key
|
16
|
-
store[key] = record
|
17
|
-
record
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def find_by_key(key)
|
22
|
-
store[key]
|
23
|
-
end
|
24
|
-
|
25
|
-
def find(query)
|
26
|
-
records = store.values
|
27
|
-
records = filter_kind(query.kind, records)
|
28
|
-
records = apply_filters(query.filters, records)
|
29
|
-
records = apply_sorts(query.sorts, records)
|
30
|
-
records = apply_offset(query.offset, records)
|
31
|
-
records = apply_limit(query.limit, records)
|
32
|
-
records
|
33
|
-
end
|
34
|
-
|
35
|
-
def delete_by_key(key)
|
36
|
-
store.delete(key)
|
37
|
-
nil
|
38
|
-
end
|
39
|
-
|
40
|
-
def delete(query)
|
41
|
-
records = find(query)
|
42
|
-
store.delete_if do |key, record|
|
43
|
-
records.include?(record)
|
44
|
-
end
|
45
|
-
nil
|
46
|
-
end
|
47
|
-
|
48
|
-
def count(query)
|
49
|
-
find(query).length
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
attr_reader :store
|
55
|
-
|
56
|
-
def filter_kind(kind, records)
|
57
|
-
records.select do |record|
|
58
|
-
record[:kind] == kind
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def apply_filters(filters, records)
|
63
|
-
records.select do |record|
|
64
|
-
filters.all? do |filter|
|
65
|
-
value = record[filter.field]
|
66
|
-
case filter.operator
|
67
|
-
when '<'; value < filter.value
|
68
|
-
when '<='; value <= filter.value
|
69
|
-
when '>'; value > filter.value
|
70
|
-
when '>='; value >= filter.value
|
71
|
-
when '='; value == filter.value
|
72
|
-
when '!='; value != filter.value
|
73
|
-
when 'contains?'; filter.value.include?(value)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def apply_sorts(sorts, records)
|
80
|
-
records.sort { |record1, record2| compare_records record1, record2, sorts }
|
81
|
-
end
|
82
|
-
|
83
|
-
def compare_records(record1, record2, sorts)
|
84
|
-
sorts.each do |sort|
|
85
|
-
result = compare_record record1, record2, sort
|
86
|
-
return result if result
|
87
|
-
end
|
88
|
-
0
|
89
|
-
end
|
90
|
-
|
91
|
-
def compare_record(record1, record2, sort)
|
92
|
-
field1, field2 = record1[sort.field], record2[sort.field]
|
93
|
-
field1 == field2 ? nil :
|
94
|
-
field1 < field2 && sort.ascending? ? -1 :
|
95
|
-
field1 > field2 && sort.descending? ? -1 : 1
|
96
|
-
end
|
97
|
-
|
98
|
-
def generate_key
|
99
|
-
@id_counter += 1
|
100
|
-
end
|
101
|
-
|
102
|
-
def apply_offset(offset, records)
|
103
|
-
return records unless offset
|
104
|
-
records.drop offset
|
105
|
-
end
|
106
|
-
|
107
|
-
def apply_limit(limit, records)
|
108
|
-
return records unless limit
|
109
|
-
records.take(limit)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|