cabi 0.1.0
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 +7 -0
- data/README.md +67 -0
- data/Rakefile +8 -0
- data/bin/cabi +35 -0
- data/cabi.gemspec +18 -0
- data/data/cabi-cache.tar.gz +0 -0
- data/data/cabi.svg +21 -0
- data/lib/cabi.rb +23 -0
- data/lib/cache.rb +40 -0
- data/lib/datafile.rb +92 -0
- data/lib/hash.rb +19 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 83fa2db5429675243c8acd14559770b0f65fd5f2
|
4
|
+
data.tar.gz: 5fb58665d172b8e4ba324fc316fea0fc50ec2436
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b4d55e6e7c80c0c49565eeffe659866662adac9b4668faab05f11c73b315816af9902044cd313e6814b26069a3dea09727ccf85960cd2210c15104801af40b90
|
7
|
+
data.tar.gz: 34b74e174b4396ec9d7073bb501549e8a98e8c0dd7eca7d92882aad6d0bc2e26b592ae87abb3449485f9859a9c05bf8feabbb1122030e1fe4fd74c28d4c9dc9a
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# <img src="https://rawgithub.com/briangonzalez/cabi-gem/master/data/cabi.svg" width=30 style="margin-right: 10px"> Cabi
|
2
|
+
|
3
|
+
A simple, flat-file datastore for Ruby.
|
4
|
+
|
5
|
+
### Getting Started
|
6
|
+
|
7
|
+
Cabi is a flat-file datastore where data is stored by directory stucture and accessed by colon-delimited strings. Here's how to get started:
|
8
|
+
|
9
|
+
``` bash
|
10
|
+
$ gem install cabi
|
11
|
+
$ cabi init --mock
|
12
|
+
```
|
13
|
+
|
14
|
+
Then access your data like so:
|
15
|
+
|
16
|
+
```bash
|
17
|
+
$ irb
|
18
|
+
> require 'cabi'
|
19
|
+
> Cabi::Cache.read('pages:about:body')
|
20
|
+
=> "<h1>Hello, Cabi!</h1>"
|
21
|
+
```
|
22
|
+
|
23
|
+
### Usage
|
24
|
+
|
25
|
+
Assuming your `cabi-cache` folder has the following structure:
|
26
|
+
|
27
|
+
- my-project
|
28
|
+
|
|
29
|
+
|--cabi-cache
|
30
|
+
|-- info.yml
|
31
|
+
|-- pages
|
32
|
+
| |-- about
|
33
|
+
| |-- body.html
|
34
|
+
| |-- meta.yml
|
35
|
+
|
|
36
|
+
|-- posts
|
37
|
+
|-- some-article
|
38
|
+
|-- index.html
|
39
|
+
|-- nav.html
|
40
|
+
|
41
|
+
|
42
|
+
You could then query your data like so:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
Cabi.read('pages:about:body') # returns contents of page/about/body.html
|
46
|
+
Cabi.read('pages:about:meta:foo:bar') # returns contents of ['foo']['bar'] in page/about/meta.yml hash
|
47
|
+
Cabi.read('info:foo:bar:baz') # returns contents of ['foo']['bar']['baz'] in info.yml hash
|
48
|
+
Cabi.read('posts:some-article:index') # returns contents of posts/some-article/index.html
|
49
|
+
Cabi.read('posts:some-article:index.html') # returns contents of posts/some-article/index.html
|
50
|
+
```
|
51
|
+
|
52
|
+
### Custom Cache Directory
|
53
|
+
|
54
|
+
Cabi assumes that your cache directory is either a folder at the top level of your project with a `.cabi-cache` file in it (to indicate that it's the cache directory). If one is not found, the cache directory defaults to `./cabi-cache`.
|
55
|
+
|
56
|
+
For instance, if you had a folder called `super-cache` located inside of your project's root that had a file called `.cabi-cache` inside of it, this folder would be treated as your cache directory.
|
57
|
+
|
58
|
+
### Questions?
|
59
|
+
|
60
|
+
Find me online [@brianmgonzalez](http://twitter.com/brianmgonzalez)
|
61
|
+
|
62
|
+
### Icon <img src="https://rawgithub.com/briangonzalez/cabi-gem/master/data/cabi.svg" width=20 style="margin-right: 10px">
|
63
|
+
|
64
|
+
[Cabi Icon](http://thenounproject.com/noun/file-cabinet/#icon-No22117) designed by Michela Tannoia, from The Noun Project.
|
65
|
+
|
66
|
+
### Tests
|
67
|
+
Run the test suite by running `rake test` in the parent directory.
|
data/Rakefile
ADDED
data/bin/cabi
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "thor"
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
CACHE_DIR = 'cabi-cache'
|
6
|
+
|
7
|
+
class CabiCLI < Thor
|
8
|
+
|
9
|
+
desc "init", "Initialize Cabi cache directory (use --mock to create fake data, use --target to specify your own directory)"
|
10
|
+
method_options :mock => :boolean, :target => :string
|
11
|
+
def init
|
12
|
+
|
13
|
+
target = options[:target] || CACHE_DIR
|
14
|
+
FileUtils.mkdir( target )
|
15
|
+
|
16
|
+
if options[:mock]
|
17
|
+
f = File.expand_path( "../../data/cabi-cache.tar.gz", __FILE__ )
|
18
|
+
`tar -xf #{f} --strip-components=1 -C #{target}`
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "clean", "Remove Cabi cache directory"
|
24
|
+
method_options :force => :boolean
|
25
|
+
def clean
|
26
|
+
if options[:force]
|
27
|
+
FileUtils.rm_rf( CACHE_DIR ) if options[:force]
|
28
|
+
else
|
29
|
+
puts "Not cleaning without --force"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
CabiCLI.start
|
data/cabi.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'cabi'
|
3
|
+
s.version = '0.1.0'
|
4
|
+
s.summary = "A simple, flat-file datastore for Ruby."
|
5
|
+
|
6
|
+
s.description = "Cabi is a flat-file datastore where data is stored by directory stucture and accessed by colon-delimited strings."
|
7
|
+
s.authors = ["Brian Gonzalez"]
|
8
|
+
s.email = 'me@briangonzalez.org'
|
9
|
+
s.homepage = 'http://github.com/briangonzalez/cabi-gem'
|
10
|
+
s.license = 'MIT'
|
11
|
+
|
12
|
+
s.files = Dir['[A-Z]*', 'cabi.gemspec', '{bin,lib,conf,web,data}/**/*'] - ['Gemfile.lock']
|
13
|
+
s.executables << 'cabi'
|
14
|
+
|
15
|
+
s.add_dependency "thor", "~> 0.18", ">= 0.18.1"
|
16
|
+
|
17
|
+
s.required_ruby_version = '>= 1.9.3'
|
18
|
+
end
|
Binary file
|
data/data/cabi.svg
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
<svg xmlns:x="http://ns.adobe.com/Extensibility/1.0/" xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/" xmlns:graph="http://ns.adobe.com/Graphs/1.0/" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Your_Icon" x="0px" y="0px" width="100px" height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
2
|
+
<switch>
|
3
|
+
<foreignObject requiredExtensions="http://ns.adobe.com/AdobeIllustrator/10.0/" x="0" y="0" width="1" height="1">
|
4
|
+
</foreignObject>
|
5
|
+
<g i:extraneous="self">
|
6
|
+
<g>
|
7
|
+
<path d="M88.743,10.01c-0.054-5.781-7.651-9.701-7.982-9.869C80.576,0.048,80.373,0,80.166,0H19.71 c-0.208,0-0.411,0.048-0.595,0.141c-0.338,0.171-8.269,4.245-7.996,10.223c0.001,0.012,0.008,0.023,0.008,0.035 C11.047,10.753,11,11.12,11,11.496v76.741c0,2.899,2.522,5.259,5.622,5.259h4.202v1.245c0,2.899,2.523,5.259,5.623,5.259h0.71 c3.1,0,5.622-2.359,5.622-5.259v-1.245h34.441v1.245c0,2.899,2.522,5.259,5.622,5.259h0.71c3.1,0,5.623-2.359,5.623-5.259v-1.245 h4.202c3.099,0,5.622-2.359,5.622-5.259V11.496C89,10.977,88.895,10.485,88.743,10.01z M86.275,30.158H13.725V11.496 c0-1.403,1.301-2.545,2.897-2.545h66.756c1.598,0,2.897,1.142,2.897,2.545V30.158z M13.725,31.803h72.551v21.769H13.725V31.803z M20.035,2.616h59.807c1.205,0.652,3.23,2.016,4.652,3.728c-0.361-0.068-0.734-0.105-1.116-0.105H16.622 c-0.435,0-0.854,0.058-1.261,0.145C16.784,4.658,18.822,3.274,20.035,2.616z M30.055,94.741c0,1.403-1.301,2.546-2.897,2.546 h-0.71c-1.598,0-2.898-1.143-2.898-2.546v-1.245h6.506V94.741z M76.451,94.741c0,1.403-1.301,2.546-2.898,2.546h-0.71 c-1.597,0-2.897-1.143-2.897-2.546v-1.245h6.506V94.741z M83.378,90.783H16.622c-1.597,0-2.897-1.143-2.897-2.546V55.215h72.551 v33.022C86.275,89.641,84.976,90.783,83.378,90.783z"/>
|
8
|
+
<path d="M60.804,20.102c0,0.675-0.677,1.244-1.478,1.244H40.508c-0.802,0-1.479-0.569-1.479-1.244v-4.228h-2.725v4.228 c0,2.181,1.886,3.956,4.203,3.956h18.818c2.316,0,4.202-1.775,4.202-3.956v-4.228h-2.725V20.102z"/>
|
9
|
+
<path d="M26.328,34.064H16.162c-0.455,0-0.824,0.367-0.824,0.82v3.602c0,0.453,0.369,0.821,0.824,0.821s0.825-0.368,0.825-0.821 v-2.779h9.341c0.455,0,0.826-0.369,0.826-0.822S26.783,34.064,26.328,34.064z"/>
|
10
|
+
<path d="M16.162,41.133c-0.455,0-0.824,0.368-0.824,0.82v3.254c0,0.453,0.369,0.821,0.824,0.821s0.825-0.368,0.825-0.821v-3.254 C16.987,41.501,16.617,41.133,16.162,41.133z"/>
|
11
|
+
<path d="M60.43,39.273v4.228c0,0.675-0.678,1.243-1.48,1.243H40.131c-0.801,0-1.479-0.568-1.479-1.243v-4.228h-2.724v4.228 c0,2.181,1.886,3.956,4.202,3.956h18.818c2.318,0,4.205-1.775,4.205-3.956v-4.228H60.43z"/>
|
12
|
+
<path d="M60.43,65.609c0,0.675-0.678,1.245-1.48,1.245H40.131c-0.801,0-1.479-0.57-1.479-1.245v-4.228h-2.724v4.228 c0,2.182,1.886,3.957,4.202,3.957h18.818c2.318,0,4.205-1.775,4.205-3.957v-4.228H60.43V65.609z"/>
|
13
|
+
<path d="M16.622,21.19c-0.455,0-0.825,0.368-0.825,0.821v2.6c0,0.454,0.37,0.822,0.825,0.822s0.825-0.368,0.825-0.822v-2.6 C17.447,21.558,17.077,21.19,16.622,21.19z"/>
|
14
|
+
<path d="M28.698,10.675H16.622c-0.455,0-0.825,0.368-0.825,0.821v5.963c0,0.454,0.37,0.822,0.825,0.822s0.825-0.368,0.825-0.822 v-5.141h11.251c0.455,0,0.825-0.368,0.825-0.822C29.523,11.043,29.153,10.675,28.698,10.675z"/>
|
15
|
+
<path d="M28.698,57.475H16.622c-0.455,0-0.825,0.369-0.825,0.822v4.252c0,0.453,0.37,0.82,0.825,0.82s0.825-0.367,0.825-0.82 v-3.432h11.251c0.455,0,0.825-0.367,0.825-0.82S29.153,57.475,28.698,57.475z"/>
|
16
|
+
<path d="M16.622,65.628c-0.455,0-0.825,0.368-0.825,0.822v5.853c0,0.453,0.37,0.821,0.825,0.821s0.825-0.368,0.825-0.821V66.45 C17.447,65.996,17.077,65.628,16.622,65.628z"/>
|
17
|
+
<path d="M16.622,77.12c-0.455,0-0.825,0.368-0.825,0.822v3.034c0,0.452,0.37,0.82,0.825,0.82s0.825-0.368,0.825-0.82v-3.034 C17.447,77.488,17.077,77.12,16.622,77.12z"/>
|
18
|
+
</g>
|
19
|
+
</g>
|
20
|
+
</switch>
|
21
|
+
</svg>
|
data/lib/cabi.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
Dir.glob( File.expand_path( '..', __FILE__) + '/*.rb' ).each do |f|
|
5
|
+
require File.join( File.expand_path( '..', f), File.basename(f, File.extname(f)) )
|
6
|
+
end
|
7
|
+
|
8
|
+
module Cabi
|
9
|
+
|
10
|
+
DELIMITER = ':'
|
11
|
+
YAML_EXT = '.yml'
|
12
|
+
CABI_CACHE_ID = '.cabi-cache'
|
13
|
+
CABI_CACHE_DIR = './cabi-cache'
|
14
|
+
|
15
|
+
def self.read(id)
|
16
|
+
Cache.read(id)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.write(id, content)
|
20
|
+
Cache.write(id, content)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/lib/cache.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Cabi
|
2
|
+
|
3
|
+
class Cache
|
4
|
+
|
5
|
+
def self.read(id)
|
6
|
+
DataFile.contents(id) || nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.write(id, content)
|
10
|
+
file = DataFile.write(id, content)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.user_cache_dir
|
14
|
+
dir = false
|
15
|
+
|
16
|
+
Dir.foreach('.') do |item|
|
17
|
+
next if item == '.' or item == '..'
|
18
|
+
if File.directory?(item) and File.exists?( File.join(item, CABI_CACHE_ID) )
|
19
|
+
dir = item
|
20
|
+
end
|
21
|
+
break if dir
|
22
|
+
end
|
23
|
+
|
24
|
+
dir
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
# Helpers for setting/getting cache dir.
|
30
|
+
def self.cache_dir
|
31
|
+
@@cache_dir ||= Cache.user_cache_dir || CABI_CACHE_DIR
|
32
|
+
raise LoadError.new "Could not find cabi cache folder!" unless File.exists? @@cache_dir
|
33
|
+
@@cache_dir
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.reset_cache_dir
|
37
|
+
@@cache_dir = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/datafile.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
module Cabi
|
2
|
+
|
3
|
+
class DataFile
|
4
|
+
|
5
|
+
def self.contents(id)
|
6
|
+
return File.read( self.file(id) ) if self.file_exists?(id)
|
7
|
+
return File.read( self.yaml_file(id) ) if self.yaml_exists?(id)
|
8
|
+
return File.read( self.non_extension_file(id) ) if self.non_extension_file(id)
|
9
|
+
return self.sub_yaml(id)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.write(id, content)
|
13
|
+
file = self.file_yaml_or_non_extension_file(id)
|
14
|
+
new_file = self.file(id)
|
15
|
+
|
16
|
+
if not file
|
17
|
+
parent = File.expand_path( '..', new_file )
|
18
|
+
FileUtils.mkdir_p(parent) unless File.exists?(parent)
|
19
|
+
FileUtils.touch(new_file) unless File.exists?(new_file)
|
20
|
+
file = new_file
|
21
|
+
end
|
22
|
+
|
23
|
+
File.open( file, 'w') {|f| f.write(content) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.exists?(id)
|
27
|
+
self.file_exists?(id) or self.yaml_exists?(id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.file_exists?(id)
|
31
|
+
File.exists?( self.file(id) )
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.yaml_exists?(id)
|
35
|
+
File.exists?( self.yaml_file(id) )
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.file_yaml_or_non_extension_file(id)
|
39
|
+
return self.file(id) if self.file_exists?(id)
|
40
|
+
return self.yaml_file(id) if self.yaml_exists?(id)
|
41
|
+
return self.non_extension_file(id) if self.non_extension_file(id)
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.file(id)
|
46
|
+
id = id.split( DELIMITER )
|
47
|
+
id = [Cabi.cache_dir] + id
|
48
|
+
File.join( *id )
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.yaml_file(id)
|
52
|
+
File.join( self.file(id) + YAML_EXT )
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.file_parent(id)
|
56
|
+
File.dirname( self.file(id) )
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.non_extension_file(id)
|
60
|
+
base = id.split( DELIMITER ).last
|
61
|
+
|
62
|
+
file = false
|
63
|
+
Dir.glob( self.file_parent(id) + '/*' ).each do |f|
|
64
|
+
file = File.join(f) if File.basename(f, File.extname(f)) == base
|
65
|
+
break if file
|
66
|
+
end
|
67
|
+
|
68
|
+
file
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.sub_yaml(id)
|
72
|
+
id = id.split( DELIMITER )
|
73
|
+
val = false
|
74
|
+
id.each_with_index do |key, index|
|
75
|
+
break if val
|
76
|
+
|
77
|
+
a = [Cabi.cache_dir] + id[0..index]
|
78
|
+
a[ a.length - 1 ] = a[a.length - 1 ] + YAML_EXT
|
79
|
+
f = File.join( *a )
|
80
|
+
|
81
|
+
if File.exists? f
|
82
|
+
data = YAML.load( File.read(f) )
|
83
|
+
val = data.access( id[index+1..-1].join(DELIMITER) )
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
val
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/lib/hash.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
class Hash
|
3
|
+
|
4
|
+
def access(path)
|
5
|
+
val = false
|
6
|
+
|
7
|
+
path.split( Cabi::DELIMITER ).each do |p|
|
8
|
+
if p.to_i.to_s == p
|
9
|
+
val = self[p.to_i]
|
10
|
+
else
|
11
|
+
val = self[p.to_s] || self[p.to_sym]
|
12
|
+
end
|
13
|
+
break unless val
|
14
|
+
end
|
15
|
+
|
16
|
+
val
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cabi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Gonzalez
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-09-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.18'
|
20
|
+
- - '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.18.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.18'
|
30
|
+
- - '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.18.1
|
33
|
+
description: Cabi is a flat-file datastore where data is stored by directory stucture
|
34
|
+
and accessed by colon-delimited strings.
|
35
|
+
email: me@briangonzalez.org
|
36
|
+
executables:
|
37
|
+
- cabi
|
38
|
+
extensions: []
|
39
|
+
extra_rdoc_files: []
|
40
|
+
files:
|
41
|
+
- Rakefile
|
42
|
+
- README.md
|
43
|
+
- cabi.gemspec
|
44
|
+
- bin/cabi
|
45
|
+
- lib/cabi.rb
|
46
|
+
- lib/cache.rb
|
47
|
+
- lib/datafile.rb
|
48
|
+
- lib/hash.rb
|
49
|
+
- data/cabi-cache.tar.gz
|
50
|
+
- data/cabi.svg
|
51
|
+
homepage: http://github.com/briangonzalez/cabi-gem
|
52
|
+
licenses:
|
53
|
+
- MIT
|
54
|
+
metadata: {}
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 1.9.3
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 2.0.3
|
72
|
+
signing_key:
|
73
|
+
specification_version: 4
|
74
|
+
summary: A simple, flat-file datastore for Ruby.
|
75
|
+
test_files: []
|