cabi 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|