store2 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 462d37b0c81d0e774272fa08c03f0525d7556a6f
4
- data.tar.gz: b9f70df4a2d8b3f02ffdaa184bf9700a598e8d10
3
+ metadata.gz: f1fb7e50d7080a31af00eaab76aad6dbb8774f89
4
+ data.tar.gz: e9945689ec31a7df9d31b53d0ab435ac8f062b9d
5
5
  SHA512:
6
- metadata.gz: db6596b207fa4d09bdcd3df0037095e8513de1dab9ee7930d50dac15cabf93f0c06884583ad2e53b5f11431bf73447e165a12eca251667274759faafc5d38581
7
- data.tar.gz: 3f8af30002e9425e0804cbace7eb8ac1e15e1c8577ad62241c5b57198802c66da08b34587a7a4e53d9eb082e2905851cc8527ffae758c80556f9c3e9644d6d1b
6
+ metadata.gz: d0d209a20596ed072c6c1e22b900b21aed3079c77dd389448fbdf3d21eb4fe3365e16740c9efc139467c2096d40fed6bcaa87087830b4e455b41d710825515aa
7
+ data.tar.gz: c8e07eddbdccbbc7f83e4e10a48fdb27aa42f40397c7a3e6bbea215f97ffa1f140cef981c3032ae56bea3419aaa48af240d22f879feebf8e9f70c8844776accf
data/.gitignore CHANGED
@@ -12,3 +12,5 @@
12
12
  *.o
13
13
  *.a
14
14
  mkmf.log
15
+ test.yml
16
+ test_other.yml
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in store2.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem "rspec"
8
+ end
data/README.md CHANGED
@@ -28,28 +28,28 @@ require "store2"
28
28
 
29
29
  ```ruby
30
30
  store2 = Store2.open("test.yml")
31
- # => <#Store2::File:0x00f28746a47 @filename = "test.yml">
31
+ # => #<Store2::File:0x00f28746a47 @filename = "test.yml">
32
32
  ```
33
33
 
34
34
  ### Get root-scoped store object
35
35
 
36
36
  ```ruby
37
37
  root_scoped = store2.build
38
- # => <#Store2::Scoped:0x00f2d746a41 @keys = []>
38
+ # => #<Store2::Scoped:0x00f2d746a41 @keys = []>
39
39
  ```
40
40
 
41
41
  ### Get scoped store object
42
42
 
43
43
  ```ruby
44
44
  user_scoped = store2.scoped("users", "72AC97F03A")
45
- # => <#Store2::Scoped:0x00a2d746a91 @keys = ["users", "72AC97F03A"]
45
+ # => #<Store2::Scoped:0x00a2d746a91 @keys = ["users", "72AC97F03A"]
46
46
  ```
47
47
 
48
48
  ### Get scoped store object out of another scoped store object
49
49
 
50
50
  ```ruby
51
51
  items_scoped = user_scoped.scoped("items")
52
- # => <#Store2::Scoped:0x00922faa907 @keys = ["users", "72AC97F03A", "items"]
52
+ # => #<Store2::Scoped:0x00922faa907 @keys = ["users", "72AC97F03A", "items"]
53
53
  ```
54
54
 
55
55
  ### Reading the value
@@ -1,5 +1,13 @@
1
- require "store2/version"
1
+ require "yaml"
2
+
3
+ %w[
4
+ version
5
+
6
+ facade
7
+ file
8
+ scoped
9
+ ].each { |name| require "store2/#{name}" }
2
10
 
3
11
  module Store2
4
- # Your code goes here...
12
+ extend Facade
5
13
  end
@@ -0,0 +1,17 @@
1
+ module Store2
2
+ module Facade
3
+ def open(filename)
4
+ File.new(filename)
5
+ end
6
+
7
+ def _with_reset
8
+ _reset
9
+ yield
10
+ _reset
11
+ end
12
+
13
+ def _reset
14
+ File._reset
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,88 @@
1
+ module Store2
2
+ class File < Struct.new(:filename)
3
+ def initialize(*args)
4
+ super
5
+ @data = load
6
+ self.class.register(self)
7
+ end
8
+
9
+ def build
10
+ scoped
11
+ end
12
+
13
+ def scoped(*keys)
14
+ Scoped.new(self, keys)
15
+ end
16
+
17
+ def get(keys)
18
+ keys.inject(data) { |data, key| data.fetch(key) }
19
+ end
20
+
21
+ def set(keys, value)
22
+ get(keys[0...-1])[keys[-1]] = value
23
+ end
24
+
25
+ def has?(keys)
26
+ get(keys[0...-1]).has_key?(keys[-1])
27
+ end
28
+
29
+ def get_or_set(keys, value)
30
+ set(keys, value) unless has?(keys)
31
+ get(keys)
32
+ end
33
+
34
+ def fetch(keys, &block)
35
+ return block.call unless has?(keys)
36
+ get(keys)
37
+ end
38
+
39
+ def save
40
+ ::File.write(filename, to_yaml)
41
+ end
42
+
43
+ def _reset
44
+ create
45
+ end
46
+
47
+ protected
48
+
49
+ attr_reader :data
50
+
51
+ private
52
+
53
+ def load
54
+ return create unless ::File.exist?(filename)
55
+ YAML.load_file(filename)
56
+ end
57
+
58
+ def create
59
+ clear
60
+ save
61
+ data
62
+ end
63
+
64
+ def clear
65
+ @data = {}
66
+ end
67
+
68
+ def to_yaml
69
+ data.to_yaml
70
+ end
71
+ end
72
+
73
+ class << File
74
+ def register(instance)
75
+ instances << instance
76
+ end
77
+
78
+ def _reset
79
+ instances.each(&:_reset)
80
+ end
81
+
82
+ private
83
+
84
+ def instances
85
+ @_instances ||= []
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,35 @@
1
+ module Store2
2
+ class Scoped < Struct.new(:store, :scope)
3
+ def scoped(*keys)
4
+ Scoped.new(store, scope + keys)
5
+ end
6
+
7
+ def get(*keys)
8
+ store.get(scope + keys)
9
+ end
10
+
11
+ def set(*keys, value)
12
+ store.set(scope + keys, value)
13
+ end
14
+
15
+ def has?(*keys)
16
+ store.has?(scope + keys)
17
+ end
18
+
19
+ def get_or_set(*keys, value)
20
+ store.get_or_set(scope + keys, value)
21
+ end
22
+
23
+ def fetch(*keys, &block)
24
+ store.fetch(scope + keys, &block)
25
+ end
26
+
27
+ def save
28
+ store.save
29
+ end
30
+
31
+ def _reset
32
+ store._reset
33
+ end
34
+ end
35
+ end
@@ -1,3 +1,3 @@
1
1
  module Store2
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,34 @@
1
+ require "store2"
2
+
3
+ RSpec.configure do |config|
4
+ config.expect_with :rspec do |expectations|
5
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
6
+ end
7
+
8
+ config.mock_with :rspec do |mocks|
9
+ mocks.verify_partial_doubles = true
10
+ end
11
+
12
+ config.filter_run :focus
13
+ config.run_all_when_everything_filtered = true
14
+
15
+ config.disable_monkey_patching!
16
+
17
+ config.warnings = true
18
+
19
+ if config.files_to_run.one?
20
+ config.default_formatter = 'doc'
21
+ end
22
+
23
+ config.profile_examples = 10
24
+
25
+ config.order = :random
26
+
27
+ Kernel.srand config.seed
28
+
29
+ config.around do |example|
30
+ Store2._with_reset do
31
+ example.run
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,110 @@
1
+ module Store2
2
+ RSpec.describe File do
3
+ subject(:store) { File.new("test.yml") }
4
+
5
+ it "behaves like a value object" do
6
+ expect(store).to eq(File.new("test.yml"))
7
+ expect(store).not_to eq(File.new("test_other.yml"))
8
+ expect(store).not_to eq(nil)
9
+ expect(store).not_to eq(Object)
10
+ expect(store).not_to eq(Object.new)
11
+ end
12
+
13
+ describe "#build" do
14
+ it "builds root scoped store" do
15
+ expect(store.build).to eq(Scoped.new(store, []))
16
+ end
17
+ end
18
+
19
+ describe "#scoped" do
20
+ it "builds scoped store with passed keys" do
21
+ expect(store.scoped("users", "72AC97F03A")).to eq(
22
+ Scoped.new(store, ["users", "72AC97F03A"])
23
+ )
24
+ end
25
+ end
26
+
27
+ describe "#save" do
28
+ it "persists data" do
29
+ store.set(["my_secret"], {})
30
+ store.set(["my_secret", "password"], "is very secret")
31
+
32
+ store.save
33
+
34
+ expect(
35
+ File.new("test.yml").get(["my_secret", "password"])
36
+ ).to eq("is very secret")
37
+ end
38
+ end
39
+
40
+ describe "#get and #set" do
41
+ it "gets the value given list of keys" do
42
+ store.set(["hello"], {})
43
+ store.set(["hello", "world"], {})
44
+ store.set(["hello", "world", "test"], "12345")
45
+
46
+ expect(store.get(["hello", "world", "test"])).to eq("12345")
47
+ end
48
+ end
49
+
50
+ describe "#has?" do
51
+ it "is true if key is present" do
52
+ store.set(["hello"], {})
53
+ store.set(["hello", "world"], {})
54
+ store.set(["hello", "world", "test"], "12345")
55
+
56
+ expect(store.has?(["hello", "world", "test"])).to eq(true)
57
+ end
58
+
59
+ it "is false if key is not present" do
60
+ store.set(["hello"], {})
61
+ store.set(["hello", "world"], {})
62
+
63
+ expect(store.has?(["hello", "world", "test"])).to eq(false)
64
+ end
65
+ end
66
+
67
+ describe "#get_or_set" do
68
+ it "is current value if it is present" do
69
+ store.set(["hello"], {})
70
+ store.set(["hello", "world"], {})
71
+ store.set(["hello", "world", "test"], "09876")
72
+
73
+ expect(store.get_or_set(["hello", "world", "test"], "12345")).to eq("09876")
74
+ end
75
+
76
+ it "is default value if it is not present" do
77
+ store.set(["hello"], {})
78
+ store.set(["hello", "world"], {})
79
+
80
+ expect(store.get_or_set(["hello", "world", "test"], "12345")).to eq("12345")
81
+ end
82
+
83
+ it "makes the value present if it wasn't" do
84
+ store.set(["hello"], {})
85
+ store.set(["hello", "world"], {})
86
+ store.get_or_set(["hello", "world", "test"], "12345")
87
+
88
+ expect(store.get(["hello", "world", "test"])).to eq("12345")
89
+ end
90
+ end
91
+
92
+ describe "#fetch" do
93
+ it "behaves like get if value is present" do
94
+ store.set(["hello"], {})
95
+ store.set(["hello", "world"], {})
96
+ store.set(["hello", "world", "test"], "09876")
97
+
98
+ expect(store.fetch(["hello", "world", "test"]) { fail }).to eq("09876")
99
+ end
100
+
101
+ it "calls block if value is not present" do
102
+ store.set(["hello"], {})
103
+ store.set(["hello", "world"], {})
104
+
105
+ expect { store.fetch(["hello", "world", "test"]) { fail } }
106
+ .to raise_error(RuntimeError)
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,133 @@
1
+ module Store2
2
+ RSpec.describe Scoped do
3
+ subject(:root) { Scoped.new(store, []) }
4
+ subject(:scoped) { Scoped.new(store, ["users", "72AC97F03A"]) }
5
+
6
+ let(:store) { File.new("test.yml") }
7
+ let(:other_store) { File.new("test_other.yml") }
8
+
9
+ before do
10
+ expect(root.get).to eq({})
11
+
12
+ root.set("users", { "72AC97F03A" => {} })
13
+ end
14
+
15
+ it "behaves like a value object" do
16
+ expect(root).to eq(Scoped.new(store, []))
17
+ expect(scoped).to eq(Scoped.new(store, ["users", "72AC97F03A"]))
18
+
19
+ expect(root).not_to eq(Scoped.new(store, ["hello"]))
20
+ expect(root).not_to eq(Scoped.new(other_store, []))
21
+
22
+ expect(root).not_to eq(nil)
23
+ expect(root).not_to eq(Object)
24
+ expect(root).not_to eq(Object.new)
25
+ end
26
+
27
+ describe "#scoped" do
28
+ it "builds further scoped " do
29
+ expect(root.scoped("items", "99A")).to eq(
30
+ Scoped.new(store, ["items", "99A"])
31
+ )
32
+
33
+ expect(scoped.scoped("items", "99A")).to eq(
34
+ Scoped.new(store, ["users", "72AC97F03A", "items", "99A"])
35
+ )
36
+ end
37
+ end
38
+
39
+ describe "#save" do
40
+ it "persists the data" do
41
+ scoped.set("items", { "123AA" => "sold" })
42
+
43
+ scoped.save
44
+
45
+ expect(
46
+ Scoped.new(File.new("test.yml"), ["users", "72AC97F03A"]).get("items", "123AA")
47
+ ).to eq("sold")
48
+ end
49
+ end
50
+
51
+ describe "#get and #set" do
52
+ it "gets the value given list of keys" do
53
+ scoped.set("hello", {})
54
+ scoped.set("hello", "world", {})
55
+ scoped.set("hello", "world", "test", "12345")
56
+
57
+ expect(scoped.get("hello", "world", "test")).to eq("12345")
58
+ expect(root.get("users", "72AC97F03A", "hello", "world", "test")).to eq("12345")
59
+ end
60
+ end
61
+
62
+ describe "#has?" do
63
+ it "is true if key is present" do
64
+ scoped.set("hello", {})
65
+ scoped.set("hello", "world", {})
66
+ scoped.set("hello", "world", "test", "12345")
67
+
68
+ expect(scoped.has?("hello", "world", "test")).to eq(true)
69
+ expect(root.has?("users", "72AC97F03A", "hello", "world", "test")).to eq(true)
70
+ end
71
+
72
+ it "is false if key is not present" do
73
+ scoped.set("hello", {})
74
+ scoped.set("hello", "world", {})
75
+
76
+ expect(scoped.has?("hello", "world", "test")).to eq(false)
77
+ expect(root.has?("users", "72AC97F03A", "hello", "world", "test")).to eq(false)
78
+ end
79
+ end
80
+
81
+ describe "#get_or_set" do
82
+ it "is current value if it is present" do
83
+ scoped.set("hello", {})
84
+ scoped.set("hello", "world", {})
85
+ scoped.set("hello", "world", "test", "09876")
86
+
87
+ expect(scoped.get_or_set("hello", "world", "test", "12345")).to eq("09876")
88
+ expect(root.get_or_set("users", "72AC97F03A", "hello", "world", "test", "12345")).to eq("09876")
89
+ end
90
+
91
+ it "is default value if it is not present" do
92
+ scoped.set("hello", {})
93
+ scoped.set("hello", "world", {})
94
+
95
+ expect(scoped.get_or_set("hello", "world", "test", "12345")).to eq("12345")
96
+ expect(root.get_or_set("users", "72AC97F03A", "hello", "world", "test", "12345")).to eq("12345")
97
+ end
98
+
99
+ it "makes the value present if it wasn't" do
100
+ scoped.set("hello", {})
101
+ scoped.set("hello", "world", {})
102
+ scoped.get_or_set("hello", "world", "test", "12345")
103
+
104
+ expect(scoped.get("hello", "world", "test")).to eq("12345")
105
+ expect(root.get("users", "72AC97F03A", "hello", "world", "test")).to eq("12345")
106
+ end
107
+ end
108
+
109
+ describe "#fetch" do
110
+ it "behaves like get if value is present" do
111
+ scoped.set("hello", {})
112
+ scoped.set("hello", "world", {})
113
+ scoped.set("hello", "world", "test", "09876")
114
+
115
+ expect(scoped.fetch("hello", "world", "test") { fail }).to eq("09876")
116
+ expect(root.fetch("users", "72AC97F03A", "hello", "world", "test") { fail }).to eq("09876")
117
+ end
118
+
119
+ it "calls block if value is not present" do
120
+ scoped.set("hello", {})
121
+ scoped.set("hello", "world", {})
122
+
123
+ expect {
124
+ scoped.fetch("hello", "world", "test") { fail }
125
+ }.to raise_error(RuntimeError)
126
+
127
+ expect {
128
+ root.fetch("users", "72AC97F03A", "hello", "world", "test") { fail }
129
+ }.to raise_error(RuntimeError)
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,7 @@
1
+ RSpec.describe Store2 do
2
+ describe ".open" do
3
+ it "opens a file" do
4
+ expect(Store2.open("test.yml")).to eq(Store2::File.new("test.yml"))
5
+ end
6
+ end
7
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: store2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleksii Fedorov
@@ -46,12 +46,20 @@ extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
48
  - ".gitignore"
49
+ - ".rspec"
49
50
  - Gemfile
50
51
  - LICENSE.txt
51
52
  - README.md
52
53
  - Rakefile
53
54
  - lib/store2.rb
55
+ - lib/store2/facade.rb
56
+ - lib/store2/file.rb
57
+ - lib/store2/scoped.rb
54
58
  - lib/store2/version.rb
59
+ - spec/spec_helper.rb
60
+ - spec/store2/file_spec.rb
61
+ - spec/store2/scoped_spec.rb
62
+ - spec/store2_spec.rb
55
63
  - store2.gemspec
56
64
  homepage: ''
57
65
  licenses:
@@ -77,4 +85,8 @@ rubygems_version: 2.2.2
77
85
  signing_key:
78
86
  specification_version: 4
79
87
  summary: Persistence in YAML files, yay!
80
- test_files: []
88
+ test_files:
89
+ - spec/spec_helper.rb
90
+ - spec/store2/file_spec.rb
91
+ - spec/store2/scoped_spec.rb
92
+ - spec/store2_spec.rb