cabi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
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: []