Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
adamhunter committed Jun 12, 2012
0 parents commit 9ca21cf
Show file tree
Hide file tree
Showing 18 changed files with 404 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
*.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
2 changes: 2 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--color
--format progress
1 change: 1 addition & 0 deletions .rvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rvm use --create default@dokument
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source 'https://rubygems.org'

# Specify your gem's dependencies in dokument.gemspec
gemspec
22 changes: 22 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Copyright (c) 2012 Adam Hunter

MIT License

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
54 changes: 54 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Dokument

TODO: Write a gem description

## Installation

Add this line to your application's Gemfile:

gem 'dokument'

And then execute:

$ bundle

Or install it yourself as:

$ gem install dokument

## Usage

TODO: Write usage instructions here

### Notes

MapReduce query for extracting entities with secondary index search
{
"inputs":{
"bucket":"mybucket",
"index":"field1_bin",
"start":"val3",
"end":"val4"
},
"query":[
{
"map":{
"language":"javascript",
"source":"
function(value, keydata, arg){
return [value];
}
",
"keep":true
}
}
]
}

## Contributing

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
2 changes: 2 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env rake
require "bundler/gem_tasks"
20 changes: 20 additions & 0 deletions dokument.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- encoding: utf-8 -*-
require File.expand_path('../lib/dokument/version', __FILE__)

Gem::Specification.new do |gem|
gem.authors = ["Adam Hunter"]
gem.email = ["adamhunter@me.com"]
gem.description = %q{Provides a ripple document to give models 1 or n file attachments.}
gem.summary = %q{Riak backed model attachments}
# gem.homepage = ""

gem.files = `git ls-files`.split($\)
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
gem.name = "dokument"
gem.require_paths = ["lib"]
gem.version = Dokument::VERSION

gem.add_dependency "riak-client", "~> 1.0.3"
gem.add_development_dependency "rspec", "~> 2.10.0"
end
14 changes: 14 additions & 0 deletions lib/dokument.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require 'riak'

module Dokument

def self.client
@client ||= Riak::Client.new
end

end

require "dokument/attachment"
require "dokument/association"
require "dokument/model"
require "dokument/version"
13 changes: 13 additions & 0 deletions lib/dokument/association.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Dokument
class Association

attr_accessor :name, :key, :bucket

def initialize(name, options = {})
self.name = name
self.bucket = options[:bucket] || name.to_s
self.key = options[:key] || :id
end

end
end
42 changes: 42 additions & 0 deletions lib/dokument/attachment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
require 'forwardable'

module Dokument
class Attachment
extend Forwardable

delegate %w[data data= content_type content_type=] => :robject

attr_reader :model, :association

def initialize(model, association)
@model = model
@association = association
end

def robject
@robject ||= bucket.get_or_new(model.send(association.key).to_s)
end

def save
raise IncompleteError.new("Attachment is missing content_type or data (#{inspect})") unless complete?
robject.store
end

def incomplete?
content_type.nil? || data.nil?
end

def complete?
!incomplete?
end

private

def bucket
Dokument.client[association.bucket]
end

class IncompleteError < StandardError ; end

end
end
38 changes: 38 additions & 0 deletions lib/dokument/model.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module Dokument
module Model

def self.included(base)
base.extend ClassMethods
end

module ClassMethods
def dokuments
@dokuments ||= Hash.new
end

def dokument(name, options={})
dokuments[name] = Association.new(name)
add_association_reader(name)
end

private

def add_association_reader(name)
define_method(name) do
get_attachment(name) || set_attachment(name)
end
end
end

private

def get_attachment(name)
instance_variable_get(:"@_#{name}")
end

def set_attachment(name)
instance_variable_set(:"@_#{name}", Dokument::Attachment.new(self, self.class.dokuments[name]))
end

end
end
3 changes: 3 additions & 0 deletions lib/dokument/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module Dokument
VERSION = "1.0.0.alpha"
end
46 changes: 46 additions & 0 deletions spec/dokument/association_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
require 'spec_helper'

describe Dokument::Association do

before :each do
@association = Dokument::Association.new(:file)
end

it "take a name upon initialization" do
@association.name.should eq(:file)
end

describe "attributes" do
%w[name bucket key].each do |attribute|
it "has a #{attribute}" do
@association.should respond_to(attribute)
end
end
end

describe "defaults" do
it "defaults the model key to :id" do
@association.key.should eq(:id)
end

it "defaults the bucket to the string version of the name" do
@association.bucket.should eq('file')
end
end

describe "initialization options" do
before :each do
@association = Dokument::Association.new(:file, :bucket => 'files_bucket', :key => 'some_id')
end

it "can set the bucket name" do
@association.bucket.should eq('files_bucket')
end

it "can set the model key" do
@association.key.should eq('some_id')
end
end

end

67 changes: 67 additions & 0 deletions spec/dokument/attachment_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
require 'spec_helper'

describe Dokument::Attachment do

before :each do
@model = ExampleModel.new
@content_type = 'text/plain'
@data = 'This is an attachment.'
@attachment = @model.file
@association = @model.file.association
@attachment.content_type = @content_type
@attachment.data = @data
end

it "has a content_type" do
@attachment.content_type.should eq(@content_type)
end

it "has a data" do
@attachment.data.should eq(@data)
end

it "delegates saving to it's robject" do
@attachment.robject.should_receive(:store)
@attachment.save
end

describe "completeness" do
it "is true if the data and content_type are set" do
@attachment.should be_complete
end

it "is false if the data is nil" do
@attachment.data = nil
@attachment.should_not be_complete
end

it "is false if the content_type is nil" do
@attachment.content_type = nil
@attachment.should_not be_complete
end

it "will raise an exception if you try to save and it is not complete" do
@attachment.data = nil
expect { @attachment.save }.to raise_error(Dokument::Attachment::IncompleteError)
end
end

describe "robject" do
it "uses the attachments data" do
@attachment.robject.data.should eq(@data)
end

it "uses the attachments content_type" do
@attachment.robject.content_type.should eq(@content_type)
end

it "uses the associated model's key method for the key" do
@attachment.robject.key.should eq(@model.id.to_s)
end

it "uses the associations bucket for the bucket name" do
@attachment.robject.bucket.name.should eq(@association.bucket)
end
end

end
29 changes: 29 additions & 0 deletions spec/dokument/model_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require 'spec_helper'

describe Dokument::Model do
describe "provided class methods" do
it "adds an accessor to list all defined dokuments" do
ExampleModel.dokuments.should be_a(Hash)
end

it "will add a single dokument using the `dokument` class method" do
ExampleModel.dokument :file
ExampleModel.dokuments[:file].should be_a(Dokument::Association)
end
end

describe "provided instance methods" do
before :each do
@model = ExampleModel.new
end

it "adds an reader for the given dokument" do
@model.should respond_to(:file)
end

it "will return the Dokument::Attachment for the given reader" do
@model.file.should be_a(Dokument::Attachment)
end

end
end
Loading

0 comments on commit 9ca21cf

Please sign in to comment.