cache_box 0.0.1.pre.preview3 → 0.0.1.pre.preview8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 111176139c5bc21c2938a934ceda7d643ad1dedeed2055c7bf53782d7eabd599
4
- data.tar.gz: ebcb405c0f2de33d53ae26d758a6f80c049793fe0dda8db1c482ea6660ddb455
3
+ metadata.gz: 2121d192ceadcf66d3ddcea5bbed36e4b90d5a34749e50b3f23672f61cb8a7ea
4
+ data.tar.gz: b5c009712c162fa0b761ff4b8998645aed7a09e467e6569fbc785b76ac166b78
5
5
  SHA512:
6
- metadata.gz: 51b2fd10d3484697d46ea07ec50d5a5ff6304f3abc22ed77546bc3702410519b38c0c47e549d183f1c74e860a170715fdef4c127b1cf9da2aaf665f0d88a7ef5
7
- data.tar.gz: 67ee7653c76f8bcc9b20af7c461d9bafac6408852a6a1279eb033ff22eafbfbd7fc33dfff421a6131a5c15967e29e7604c7007d6461687a0134b1dda07081f98
6
+ metadata.gz: c4c45937029f9096bc8a8224decec4ab72faa98569043b1292d19e050826a92a8be57bdf26612e2800f82712654a444b03c66327e9a4baa5f8110444967397c3
7
+ data.tar.gz: 97dece56e4b22094415960285047136b15a1e02bea647b0c8b41eb2b762b661ef301f81b7acc376b27cc9027a4c86c7403971656cf824e9e8debc59439922ad0
@@ -2,19 +2,31 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'cache_box'
5
- spec.version = '0.0.1-preview3'
5
+ spec.version = '0.0.1-preview8'
6
6
  spec.authors = ['Codruț Constantin Gușoi']
7
- spec.email = ['codrut.gusoi+git-commit@gmail.com']
7
+ spec.email = ['codrut.gusoi+rubygems.org@gmail.com']
8
8
 
9
- spec.summary = 'A simple, fast, and easy to use file backed cache.'
9
+ spec.summary = 'A simple, fast, and easy to use local cache.'
10
10
  spec.homepage = 'https://gitlab.com/sdwolfz/cache_box_rb'
11
- spec.license = 'BSD 3-clause'
11
+ spec.license = 'BSD-3-Clause'
12
+
13
+ spec.metadata = {
14
+ 'homepage_uri' => 'https://gitlab.com/sdwolfz/cache_box_rb',
15
+ 'source_code_uri' => 'https://gitlab.com/sdwolfz/cache_box_rb'
16
+ }
12
17
 
13
18
  spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
14
19
 
15
20
  spec.files = [
16
21
  'lib/cache_box.rb',
17
- 'lib/cache_box_chain.rb',
22
+ 'lib/cache_box/helper/validate.rb',
23
+ 'lib/cache_box/scheduler/serial.rb',
24
+ 'lib/cache_box/storage/file.rb',
25
+ 'lib/cache_box/storage/memory.rb',
26
+ 'lib/cache_box/box.rb',
27
+ 'lib/cache_box/chain.rb',
28
+ 'lib/cache_box/graph.rb',
29
+ 'lib/cache_box/unit.rb',
18
30
  'LICENSE',
19
31
  'cache_box.gemspec'
20
32
  ]
@@ -1,198 +1,75 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'fileutils'
4
- require_relative 'cache_box_chain'
4
+ require 'logger'
5
5
 
6
- class CacheBox
7
- # Input:
8
- #
9
- # namespace = String | Symbol # Default: :namespace
10
- #
11
- # Output: N/A
12
- def initialize(namespace = :namespace)
13
- validate!(namespace, 'namespace')
6
+ require_relative 'cache_box/helper/validate'
14
7
 
15
- @namespace = namespace
16
- @state = { complete: {}, result: {}, storage: {} }
17
- @root = File.join(Dir.pwd, '.cache')
18
- @directory = File.join(@root, @namespace.to_s)
19
- end
8
+ require_relative 'cache_box/storage/file'
9
+ require_relative 'cache_box/storage/memory'
20
10
 
21
- # Input:
22
- #
23
- # namespace = String | Symbol # Default: :namespace
24
- #
25
- # Output: self
26
- def reset!(namespace = :namespace)
27
- initialize(namespace)
11
+ require_relative 'cache_box/box'
12
+ require_relative 'cache_box/unit'
28
13
 
29
- self
30
- end
14
+ require_relative 'cache_box/scheduler/serial'
15
+
16
+ require_relative 'cache_box/chain'
17
+ require_relative 'cache_box/graph'
18
+
19
+ class CacheBox
20
+ include CacheBox::Helper::Validate
31
21
 
32
22
  # Input:
33
23
  #
34
- # name = String | Symbol # Default: :name
35
- # args = Array[...Object]
36
- # &block = Proc(*args)
24
+ # namespace = String | Symbol # Default: :namespace
25
+ # logger = Logger
26
+ # storage = CacheBox::Storage::*
37
27
  #
38
- # Output: Object # Anything the &block returns.
39
- def with(name = :name, *args)
40
- validate!(name, 'name')
41
-
42
- name = name.to_s
43
- file = File.join(@directory, name)
44
- result = find!(name, file)
45
- return result unless result.nil?
46
-
47
- result = yield(*args)
48
-
49
- @state[:complete][name] = true
50
- @state[:result][name] = result
51
- @state[:storage].delete(name)
52
- store!(name, file)
28
+ # Output: N/A
29
+ def initialize(namespace = nil, logger: nil, storage: nil)
30
+ namespace ||= :namespace
31
+ validate_string_or_symbol!(namespace, 'namespace')
53
32
 
54
- result
33
+ @unit = ::CacheBox::Unit.new(namespace, logger: logger, storage: storage)
55
34
  end
56
35
 
57
36
  # Input:
58
37
  #
59
- # name = String | Symbol # Default: :name
60
- # args = Array[...Object]
61
- # &block = Proc(Hash{...Object => Object}, *args)
38
+ # name = String | Symbol # Default: 'name'
39
+ # args = Object
40
+ # &block = Proc(CacheBox::Box)
62
41
  #
63
42
  # Output: Object # Anything the &block returns.
64
- def with_many(name = :name, *args)
65
- validate!(name, 'name')
66
-
67
- name = name.to_s
68
- file = File.join(@directory, name)
69
- result = find!(name, file)
70
- return result unless result.nil?
71
-
72
- storage = @state[:storage][name] || {}
73
- begin
74
- result = yield(storage, *args)
75
-
76
- @state[:complete][name] = true
77
- @state[:result][name] = result
78
- @state[:storage].delete(name)
79
- store!(name, file)
80
-
81
- result
82
- ensure
83
- unless @state[:complete][name]
84
- @state[:storage][name] = storage
85
- end
86
-
87
- store!(name, file)
88
- end
43
+ def with(name = nil, args = nil, &block)
44
+ name ||= 'name'
45
+ validate_string_or_symbol!(name, 'name')
46
+ validate_block_presence!(block, '#with')
47
+
48
+ @unit.with(name, args, nil, &block)
89
49
  end
90
50
 
91
51
  # Input:
92
52
  #
93
- # name = String | Symbol # Default: :name
53
+ # name = String | Symbol # Default: 'name'
94
54
  #
95
55
  # Output: true | false
96
- def has?(name = :name)
97
- validate!(name, 'name')
98
-
99
- name = name.to_s
100
- return true if @state[:result].key?(name)
56
+ def has?(name = nil)
57
+ name ||= 'name'
58
+ validate_string_or_symbol!(name, 'name')
101
59
 
102
- file = File.join(@directory, name)
103
- load!(name, file)
104
-
105
- @state[:result].key?(name)
106
- end
107
-
108
- # Output: self
109
- def expire!
110
- @state = { complete: {}, result: {}, storage: {} }
111
- FileUtils.remove_entry_secure(@directory, true)
112
-
113
- self
60
+ @unit.has?(name)
114
61
  end
115
62
 
116
63
  # Input:
117
64
  #
118
- # name = String | Symbol # Default: :name
65
+ # name = Array[String | Symbol] # Default: []
119
66
  #
120
67
  # Output: self
121
- def expire(name = :name)
122
- validate!(name, 'name')
123
-
124
- name = name.to_s
125
- @state[:complete].delete(name)
126
- @state[:result].delete(name)
127
- @state[:storage].delete(name)
68
+ def expire!(*names)
69
+ validate_array_of_string_or_symbol!(names, 'names')
128
70
 
129
- file = File.join(@directory, name)
130
- FileUtils.remove_entry_secure(file, true)
71
+ @unit.expire!(*names)
131
72
 
132
73
  self
133
74
  end
134
-
135
- private
136
-
137
- # Input:
138
- #
139
- # arg = String | Symbol
140
- # name = String
141
- #
142
- # Output: N/A
143
- def validate!(arg, name)
144
- return if arg.is_a?(Symbol) || arg.is_a?(String)
145
-
146
- klass = arg.class
147
- value = arg.inspect
148
-
149
- raise(ArgumentError, "#{name} must be a Symbol or String, got #{klass}: #{value}")
150
- end
151
-
152
- # Input:
153
- #
154
- # name = String
155
- # file = String # Path
156
- #
157
- # Output: N/A
158
- def load!(name, file)
159
- if File.exist?(file)
160
- data = Marshal.load(File.read(file))
161
-
162
- @state[:complete][name] = data[:complete]
163
- @state[:result][name] = data[:result]
164
- @state[:store][name] = data[:store] unless data[:complete]
165
- end
166
- end
167
-
168
- # Input:
169
- #
170
- # name = String
171
- # file = String # Path
172
- #
173
- # Output: Object # Anything
174
- def find!(name, file)
175
- load!(name, file)
176
-
177
- @state[:result][name]
178
- end
179
-
180
- # Input:
181
- #
182
- # file = String # Path
183
- #
184
- # Output: N/A
185
- def store!(name, file)
186
- data = {
187
- complete: @state[:complete][name],
188
- result: @state[:result][name],
189
- }
190
- data[:store] = @state[:store][:name] unless @state[:complete][name]
191
-
192
- content = Marshal.dump(data)
193
-
194
- directory = File.dirname(file)
195
- FileUtils.mkdir_p(directory) unless Dir.exist?(directory)
196
- File.write(file, content)
197
- end
198
75
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CacheBox
4
+ # A container for references needed during execution.
5
+ class Box
6
+ attr_reader :namespace, :name, :args, :input, :stash, :logger
7
+
8
+ def initialize(namespace:, name:, args:, input:, stash:, logger:)
9
+ @namespace = namespace
10
+ @name = name
11
+ @args = args
12
+ @input = input
13
+ @stash = stash
14
+ @logger = logger
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CacheBox
4
+ class Chain
5
+ include CacheBox::Helper::Validate
6
+
7
+ # Input:
8
+ #
9
+ # namespace = String | Symbol # Default: 'namespace'
10
+ #
11
+ # Output: N/A
12
+ def initialize(namespace = nil, logger: nil, storage: nil)
13
+ namespace ||= :namespace
14
+ validate_string_or_symbol!(namespace, 'namespace')
15
+
16
+ logger ||= Logger.new(STDOUT, level: Logger::INFO)
17
+ storage ||= ::CacheBox::Storage::File.new(namespace: namespace)
18
+
19
+ @unit = ::CacheBox::Unit.new(namespace, logger: logger, storage: storage)
20
+ @chain = []
21
+ @lookup = Set.new
22
+
23
+ @namespace = namespace
24
+ @logger = logger
25
+ end
26
+
27
+ # Input:
28
+ #
29
+ # name = String | Symbol
30
+ # input = Object # Default: nil
31
+ # &block = Proc(Hash{...Object => Object}, *args)
32
+ #
33
+ # Output: self
34
+ def add(name, args = nil, &block)
35
+ validate_string_or_symbol!(name, 'name')
36
+ validate_block_presence!(block, '#add')
37
+
38
+ name_o = name
39
+ name_s = name.to_s
40
+ if @lookup.include?(name_s)
41
+ raise(
42
+ ArgumentError,
43
+ "Chain already contains a step named #{name_o.inspect}"
44
+ )
45
+ else
46
+ @lookup << name_s
47
+ end
48
+
49
+ @chain.push(
50
+ [name_o, proc { |input| @unit.with(name_s, args, input, &block) }]
51
+ )
52
+
53
+ self
54
+ end
55
+
56
+ # Output: Object # Anything the last block in the chain returns.
57
+ def run!
58
+ work = []
59
+
60
+ @chain.reverse_each do |name, callable|
61
+ work.push([name, callable])
62
+
63
+ break if @unit.has?(name)
64
+ end
65
+
66
+ result = nil
67
+ previous = nil
68
+ work.reverse_each do |name, callable|
69
+ result = callable.call(result)
70
+
71
+ @unit.clear(previous) if previous
72
+ previous = name
73
+ end
74
+
75
+ result
76
+ end
77
+
78
+ # Input:
79
+ #
80
+ # name = Array[String | Symbol] # Default: []
81
+ #
82
+ # Output: self
83
+ def expire!(*names)
84
+ validate_array_of_string_or_symbol!(names, 'names')
85
+ @unit.expire!(*names)
86
+
87
+ self
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CacheBox
4
+ class Graph
5
+ include CacheBox::Helper::Validate
6
+
7
+ # Input:
8
+ #
9
+ # namespace = String | Symbol # Default: 'namespace'
10
+ # scheduler = CacheBox::Scheduler::*
11
+ # storage = CacheBox::Storage::*
12
+ # logger = Logger
13
+ #
14
+ # Output: N/A
15
+ def initialize(namespace = nil, scheduler: nil, storage: nil, logger: nil)
16
+ namespace ||= :namespace
17
+ validate_string_or_symbol!(namespace, 'namespace')
18
+
19
+ @namespace = namespace
20
+ @logger = logger || Logger.new(STDOUT, level: Logger::INFO)
21
+ @storage = storage || ::CacheBox::Storage::File.new(namespace: @namespace)
22
+ @scheduler = scheduler || ::CacheBox::Scheduler::Serial.new(logger: @logger)
23
+ @unit = ::CacheBox::Unit.new(@namespace, logger: @logger, storage: @storage)
24
+
25
+ @nodes = {}
26
+ end
27
+
28
+ # Input:
29
+ #
30
+ # edge = String |
31
+ # Symbol |
32
+ # Hash{String | Symbol => String | Symbol | Array[String | Symbol]}
33
+ # args = Object
34
+ # &block = Proc(Hash{...Object => Object}, *args)
35
+ #
36
+ # Output: self
37
+ def node(edge, args = nil, &block)
38
+ validate_edge!(edge)
39
+ validate_block_presence!(block, '#node')
40
+
41
+ @scheduler.add(edge)
42
+ name_o = extract_name(edge)
43
+ name_s = name_o.to_s
44
+
45
+ @nodes[name_s] = [
46
+ name_o,
47
+ proc { |input| @unit.with(name_s, args, input, &block) }
48
+ ]
49
+
50
+ self
51
+ end
52
+
53
+ # Input: N/A
54
+ #
55
+ # Output: Object # Anything the last block in the chain returns.
56
+ def run!
57
+ @scheduler.run!(@nodes, @unit)
58
+ end
59
+
60
+ # Input:
61
+ #
62
+ # name = Array[String | Symbol] # Default: []
63
+ #
64
+ # Output: self
65
+ def expire!(*names)
66
+ validate_array_of_string_or_symbol!(names, 'names')
67
+ @unit.expire!(*names)
68
+
69
+ self
70
+ end
71
+
72
+ private
73
+
74
+ # Input:
75
+ #
76
+ # edge = String |
77
+ # Symbol |
78
+ # Hash{String | Symbol => String | Symbol | Array[String | Symbol]}
79
+ #
80
+ # Output: String
81
+ def extract_name(edge)
82
+ return edge.to_s if edge.is_a?(Symbol) || edge.is_a?(String)
83
+
84
+ edge.keys.first.to_s
85
+ end
86
+ end
87
+ end