hari 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +22 -0
  4. data/README.md +0 -0
  5. data/Rakefile +1 -0
  6. data/hari.gemspec +38 -0
  7. data/lib/hari/configuration/redis.rb +33 -0
  8. data/lib/hari/configuration.rb +12 -0
  9. data/lib/hari/entity/property/builder.rb +25 -0
  10. data/lib/hari/entity/property.rb +24 -0
  11. data/lib/hari/entity/repository.rb +75 -0
  12. data/lib/hari/entity/serialization/boolean.rb +43 -0
  13. data/lib/hari/entity/serialization/date.rb +21 -0
  14. data/lib/hari/entity/serialization/datetime.rb +21 -0
  15. data/lib/hari/entity/serialization/float.rb +19 -0
  16. data/lib/hari/entity/serialization/integer.rb +28 -0
  17. data/lib/hari/entity/serialization/string.rb +17 -0
  18. data/lib/hari/entity/serialization/time.rb +21 -0
  19. data/lib/hari/entity/serialization.rb +42 -0
  20. data/lib/hari/entity.rb +77 -0
  21. data/lib/hari/errors.rb +17 -0
  22. data/lib/hari/node/queries.rb +7 -0
  23. data/lib/hari/node.rb +16 -0
  24. data/lib/hari/relationship/linked_list.rb +22 -0
  25. data/lib/hari/relationship/sorted_set.rb +22 -0
  26. data/lib/hari/relationship.rb +72 -0
  27. data/lib/hari/scripts.rb +26 -0
  28. data/lib/hari/version.rb +3 -0
  29. data/lib/hari.rb +20 -0
  30. data/spec/hari/entity/repository_spec.rb +22 -0
  31. data/spec/hari/entity/serialization/boolean_spec.rb +32 -0
  32. data/spec/hari/entity/serialization/date_spec.rb +23 -0
  33. data/spec/hari/entity/serialization/datetime_spec.rb +23 -0
  34. data/spec/hari/entity/serialization/float_spec.rb +19 -0
  35. data/spec/hari/entity/serialization/integer_spec.rb +18 -0
  36. data/spec/hari/entity/serialization/string_spec.rb +13 -0
  37. data/spec/hari/entity/serialization/time_spec.rb +14 -0
  38. data/spec/hari/entity/serialization_spec.rb +24 -0
  39. data/spec/spec_helper.rb +10 -0
  40. metadata +256 -0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ Gemfile.lock
3
+ .bundle
4
+ *.rdb
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org/'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Victor Rodrigues
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/hari.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'hari/version'
7
+
8
+ Gem::Specification.new do |s|
9
+ s.name = 'hari'
10
+ s.version = Hari::VERSION
11
+ s.summary = 'Hari is a graph library on top of Redis + Lua scripts'
12
+ s.description = <<-MD
13
+ Hari is a graph library on top of Redis database + Lua scripts
14
+ MD
15
+
16
+ s.author = 'Victor Rodrigues'
17
+ s.email = 'victorc.rodrigues@gmail.com'
18
+ s.homepage = 'http://github.com/rodrigues/hari'
19
+
20
+ s.license = 'MIT'
21
+
22
+ s.files = `git ls-files`.split($/)
23
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
25
+ s.require_paths = ['lib']
26
+
27
+ s.add_dependency 'redis', '~> 3.0'
28
+ s.add_dependency 'redis-namespace', '~> 1.2'
29
+ s.add_dependency 'hiredis', '~> 0.4'
30
+ s.add_dependency 'activemodel', '~> 3.2'
31
+ s.add_dependency 'activesupport', '~> 3.2'
32
+ s.add_dependency 'yajl-ruby', '~> 1.1'
33
+
34
+ s.add_development_dependency 'bundler', '~> 1.3'
35
+ s.add_development_dependency 'rspec', '~> 2.13'
36
+ s.add_development_dependency 'rake', '~> 10.0'
37
+ s.add_development_dependency 'pry'
38
+ end
@@ -0,0 +1,33 @@
1
+ module Hari
2
+ module Configuration
3
+ module Redis
4
+
5
+ def redis
6
+ @redis || begin
7
+ self.redis = 'localhost:6379'
8
+ @redis
9
+ end
10
+ end
11
+
12
+ def redis=(server)
13
+ @redis = redis_namespace(server)
14
+ end
15
+
16
+ private
17
+
18
+ def redis_namespace(server)
19
+ return server if server.kind_of?(::Redis::Namespace)
20
+
21
+ ::Redis::Namespace.new :hari, redis_server(server)
22
+ end
23
+
24
+ def redis_server(server)
25
+ return server unless server.kind_of?(::String)
26
+
27
+ host, port = server.split(':')
28
+ ::Redis.new host: host, port: port
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ require 'hari/configuration/redis'
2
+
3
+ module Hari
4
+ module Configuration
5
+ include Redis
6
+
7
+ def configure
8
+ yield self if block_given?
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,25 @@
1
+ module Hari
2
+ class Entity
3
+ class Property
4
+ module Builder
5
+
6
+ def property(name, options = {})
7
+ attr_accessor name
8
+ validates_presence_of name if options[:required]
9
+
10
+ self.properties << Property.new(name, options)
11
+ end
12
+
13
+ def properties(*args)
14
+ options = args.extract_options!
15
+ args.each { |name| property name, options }
16
+
17
+ @properties ||= begin
18
+ self == Hari::Entity ? [] : Hari::Entity.properties.dup
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ require 'hari/entity/property/builder'
2
+
3
+ module Hari
4
+ class Entity
5
+ class Property
6
+
7
+ attr_accessor :name, :serializer, :options
8
+
9
+ def initialize(name, options = {})
10
+ @name, @options = name.to_s, options
11
+ @serializer = options.delete(:type) || Serialization::String
12
+ end
13
+
14
+ def serialize(value)
15
+ serializer.serialize(value, name: name)
16
+ end
17
+
18
+ def desserialize(value)
19
+ serializer.desserialize(value, name: name)
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,75 @@
1
+ module Hari
2
+ class Entity
3
+ module Repository
4
+ extend ActiveSupport::Concern
5
+
6
+ def create_or_update
7
+ run_callbacks(:save) { new? ? create : update }
8
+ end
9
+
10
+ alias save create_or_update
11
+
12
+ def create
13
+ run_callbacks :create do
14
+ fail Hari::ValidationsFailed, self unless valid?
15
+
16
+ @id ||= generate_id
17
+ self.created_at = Time.now
18
+ self.updated_at = Time.now
19
+ persist
20
+ end
21
+
22
+ self
23
+ end
24
+
25
+ def update
26
+ run_callbacks :update do
27
+ fail Hari::ValidationsFailed, self unless valid?
28
+
29
+ self.updated_at = Time.now.utc.iso8601
30
+ persist
31
+ end
32
+
33
+ self
34
+ end
35
+
36
+ def persist
37
+ Hari.redis.set id, to_json
38
+ end
39
+
40
+ def delete
41
+ run_callbacks :destroy do
42
+ Hari.redis.del id
43
+ @destroyed = true
44
+ end
45
+
46
+ self
47
+ end
48
+
49
+ alias destroy delete
50
+
51
+ module ClassMethods
52
+
53
+ def create(attrs = {})
54
+ new(attrs).save
55
+ end
56
+
57
+ def find(*args)
58
+ options = args.extract_options!
59
+ args.flatten!
60
+ args.one? ? find_one(args[0], options) : find_many(args, options)
61
+ end
62
+
63
+ def find_one(id, options = {})
64
+ from_json Hari.redis.get(id)
65
+ end
66
+
67
+ def find_many(ids, options = {})
68
+ Hari.redis.mget(ids).map &method(:from_json)
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,43 @@
1
+ module Hari
2
+ class Entity
3
+ module Serialization
4
+ module Boolean
5
+
6
+ MAPPINGS = {
7
+ true => true,
8
+ 'true' => true,
9
+ 'TRUE' => true,
10
+ '1' => true,
11
+ 1 => true,
12
+ 1.0 => true,
13
+ 'x' => true,
14
+ 'X' => true,
15
+ 't' => true,
16
+ 'T' => true,
17
+ false => false,
18
+ 'false' => false,
19
+ 'FALSE' => false,
20
+ '0' => false,
21
+ 0 => false,
22
+ 0.0 => false,
23
+ '' => false,
24
+ ' ' => false,
25
+ 'f' => false,
26
+ 'F' => false,
27
+ nil => false
28
+ }.freeze
29
+
30
+ def self.serialize(value, options = {})
31
+ desserialize value, options
32
+ end
33
+
34
+ def self.desserialize(value, options = {})
35
+ MAPPINGS[value].tap do |bool|
36
+ fail SerializationError, "#{options[:name]}:#{value} is not boolean" if bool.nil?
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ module Hari
2
+ class Entity
3
+ module Serialization
4
+ module Date
5
+
6
+ def self.serialize(value, options = {})
7
+ desserialize(value, options).try :iso8601
8
+ end
9
+
10
+ def self.desserialize(value, options = {})
11
+ return unless value.present?
12
+
13
+ value.kind_of?(::Date) ? value : ::Date.parse(value)
14
+ rescue
15
+ raise SerializationError, "#{options[:name]}:#{value} is an invalid date"
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module Hari
2
+ class Entity
3
+ module Serialization
4
+ module DateTime
5
+
6
+ def self.serialize(value, options = {})
7
+ desserialize(value, options).try :iso8601
8
+ end
9
+
10
+ def self.desserialize(value, options = {})
11
+ return unless value.present?
12
+
13
+ value.kind_of?(::DateTime) ? value : ::DateTime.parse(value)
14
+ rescue
15
+ raise SerializationError, "#{options[:name]}:#{value} is an invalid date time"
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ module Hari
2
+ class Entity
3
+ module Serialization
4
+ module Float
5
+
6
+ def self.serialize(value, options = {})
7
+ desserialize value, options
8
+ end
9
+
10
+ def self.desserialize(value, options = {})
11
+ Float value
12
+ rescue
13
+ raise SerializationError, "#{options[:name]}:#{value} is not a float"
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ module Hari
2
+ class Entity
3
+ module Serialization
4
+ module Integer
5
+
6
+ def self.serialize(value, options = {})
7
+ desserialize value, options
8
+ end
9
+
10
+ def self.desserialize(value, options = {})
11
+ case value
12
+ when ::String
13
+ if value =~ /^\d+$/
14
+ value.to_i
15
+ else
16
+ raise
17
+ end
18
+ else
19
+ Integer(value)
20
+ end
21
+ rescue
22
+ raise SerializationError, "#{options[:name]}:#{value} is not an integer"
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ module Hari
2
+ class Entity
3
+ module Serialization
4
+ module String
5
+
6
+ def self.serialize(value, options = {})
7
+ value.to_s if value
8
+ end
9
+
10
+ def self.desserialize(value, options = {})
11
+ value
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module Hari
2
+ class Entity
3
+ module Serialization
4
+ module Time
5
+
6
+ def self.serialize(value, options = {})
7
+ desserialize(value, options).try :strftime, '%Y%m%d%H%M%S'
8
+ end
9
+
10
+ def self.desserialize(value, options = {})
11
+ return unless value.present?
12
+
13
+ value.kind_of?(::Time) ? value : ::Time.parse(value)
14
+ rescue
15
+ raise SerializationError, "#{options[:name]}:#{value} is an invalid time"
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,42 @@
1
+ require 'hari/entity/serialization/boolean'
2
+ require 'hari/entity/serialization/date'
3
+ require 'hari/entity/serialization/datetime'
4
+ require 'hari/entity/serialization/float'
5
+ require 'hari/entity/serialization/integer'
6
+ require 'hari/entity/serialization/string'
7
+ require 'hari/entity/serialization/time'
8
+
9
+ module Hari
10
+ class Entity
11
+ module Serialization
12
+ extend ActiveSupport::Concern
13
+
14
+ def to_json
15
+ hash = self.class.properties.inject({}) do |buffer, prop|
16
+ buffer.merge prop.name => prop.serialize(send(prop.name))
17
+ end
18
+
19
+ Yajl::Encoder.encode hash
20
+ end
21
+
22
+ module ClassMethods
23
+
24
+ def from_json(source)
25
+ return if source.blank?
26
+
27
+ attrs = Yajl::Parser.parse(source).inject({}) do |buffer, (key, value)|
28
+ if prop = properties.find { |p| p.name == key }
29
+ buffer[key] = prop.desserialize(value)
30
+ end
31
+
32
+ buffer
33
+ end
34
+
35
+ new attrs
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,77 @@
1
+ require 'hari/entity/property'
2
+ require 'hari/entity/repository'
3
+ require 'hari/entity/serialization'
4
+
5
+ module Hari
6
+ class Entity
7
+ extend ActiveModel::Naming
8
+ extend ActiveModel::Callbacks
9
+ include ActiveModel::Validations
10
+ extend Property::Builder
11
+ include Repository
12
+ include Serialization
13
+
14
+ define_model_callbacks :create, :update, :destroy, :save
15
+
16
+ property :id
17
+ property :created_at, type: Time
18
+ property :updated_at, type: Time
19
+
20
+ def initialize(attrs = {})
21
+ return if attrs.blank?
22
+
23
+ attrs = attrs.with_indifferent_access
24
+
25
+ self.class.properties.each do |prop|
26
+ send("#{prop.name}=", attrs[prop.name]) if attrs[prop.name]
27
+ end
28
+ end
29
+
30
+ def attributes
31
+ self.class.properties.inject({}) do |buffer, prop|
32
+ buffer.merge prop.name => send(prop.name)
33
+ end
34
+ end
35
+
36
+ alias attribute send
37
+ alias read_attribute send
38
+
39
+ def write_attribute(name, value)
40
+ send "#{name}=", value
41
+ end
42
+
43
+ def has_attribute?(name)
44
+ respond_to? name
45
+ end
46
+
47
+ def ==(other)
48
+ other.is_a?(Hari::Entity) && self.id == other.id
49
+ end
50
+
51
+ def new?
52
+ self.id.nil?
53
+ end
54
+
55
+ alias new_record? new?
56
+
57
+ def persisted?
58
+ not new?
59
+ end
60
+
61
+ def destroyed?
62
+ @destroyed
63
+ end
64
+
65
+ def generate_id
66
+ 'ent' + ::Time.now.strftime('%Y%m%d%H%M%S') + SecureRandom.hex(3)
67
+ end
68
+
69
+ def to_s
70
+ attrs = attributes
71
+ attrs.delete 'id'
72
+
73
+ "<#{self.class} id=#{id} attributes=#{attrs}>"
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,17 @@
1
+ module Hari
2
+ class HariException < RuntimeError; end
3
+ class NotFound < HariException; end
4
+ class InvalidQuery < HariException; end
5
+ class SerializationError < HariException; end
6
+
7
+ class ValidationsFailed < HariException
8
+ attr_reader :object
9
+
10
+ def initialize(object)
11
+ @object = object
12
+ errors = @object.errors.full_messages.to_sentence
13
+ super errors
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,7 @@
1
+ module Hari
2
+ class Node < Entity
3
+ module Queries
4
+
5
+ end
6
+ end
7
+ end
data/lib/hari/node.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'hari/node/queries'
2
+
3
+ module Hari
4
+ class Node < Entity
5
+ include Hari::Node::Queries
6
+
7
+ property :model_id, required: true
8
+
9
+ def generate_id
10
+ return model_id if model_id.include?('#')
11
+
12
+ self.class.to_s.underscore + "#" + model_id.to_s
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ module Hari
2
+ class Relationship < Entity
3
+ module Backend
4
+ module LinkedList
5
+ extend self
6
+
7
+ def type
8
+ :ll
9
+ end
10
+
11
+ def create(rel)
12
+ %w(in out).each { |d| Hari.redis.lpush rel.key(d), rel.id }
13
+ end
14
+
15
+ def delete(rel)
16
+ %w(in out).each { |d| Hari.redis.lrem rel.key(d), 1, rel.id }
17
+ end
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ module Hari
2
+ class Relationship < Entity
3
+ module Backend
4
+ module SortedSet
5
+ extend self
6
+
7
+ def type
8
+ :ss
9
+ end
10
+
11
+ def create(rel)
12
+ %w(in out).each { |d| Hari.redis.zadd rel.key(d), rel.weight(d), rel.id }
13
+ end
14
+
15
+ def delete(rel)
16
+ %w(in out).each { |d| Hari.redis.zrem rel.key(d), rel.id }
17
+ end
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,72 @@
1
+ module Hari
2
+ class Relationship < Entity
3
+
4
+ properties :label, :start_node_id, :end_node_id, presence: true
5
+
6
+ def generate_id
7
+ 'rel:' + start_node.id + ':' + end_node.id + ':' + backend.id + ':' + SecureRandom.hex(3)
8
+ end
9
+
10
+ def start_node
11
+ @start_node ||= Hari::Node.find(start_node_id)
12
+ end
13
+
14
+ def end_node
15
+ @end_node ||= Hari::Node.find(end_node_id)
16
+ end
17
+
18
+ def self.create(label, start_node, end_node, attributes = {})
19
+ attrs = attributes.merge(label: label,
20
+ start_node_id: node_id(start_node),
21
+ end_node_id: node_id(end_node))
22
+ new(attrs).save
23
+ end
24
+
25
+ def self.use!(backend)
26
+ @backend = backend.kind_of?(Module) ? backend
27
+ : "Hari::Relationship::#{backend.to_s.camelize}".constantize
28
+ end
29
+
30
+ def self.backend
31
+ @backend ||= Hari::Relationship::Backend::SortedSet
32
+ end
33
+
34
+ def backend
35
+ self.class.backend
36
+ end
37
+
38
+ def weight(dir)
39
+ Time.now
40
+ end
41
+
42
+ private
43
+
44
+ def node_id(node)
45
+ node.kind_of?(::String) ? node : node.try(:id)
46
+ end
47
+
48
+ def key(dir = nil)
49
+ case dir
50
+ when nil
51
+ "#{start_node_id}:#{label}:#{end_node_id}"
52
+ else
53
+ "#{start_node_id}:#{label}:#{dir}"
54
+ end
55
+ end
56
+
57
+ def create
58
+ super
59
+ backend.create self
60
+ Hari.redis.set key, id
61
+ self
62
+ end
63
+
64
+ def delete
65
+ backend.delete self
66
+ Hari.redis.del key
67
+ super
68
+ self
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,26 @@
1
+ module Hari
2
+ module Scripts
3
+
4
+ SCRIPT_PATH = File.expand_path('../scripts', __FILE__)
5
+
6
+ def map
7
+ @scripts ||= {}
8
+ end
9
+
10
+ def load
11
+ files = Dir[SCRIPT_PATH.join('**/*.lua')]
12
+
13
+ files.each do |file|
14
+ name = file.gsub("#{SCRIPT_PATH}/", '').gsub('.lua', '')
15
+ script = File.read(file)
16
+ sha = Hari.redis.script(:load, script)
17
+ map[name] = sha
18
+ end
19
+ end
20
+
21
+ def sha(script_name)
22
+ map[script_name.to_s]
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ module Hari
2
+ VERSION = '0.0.1'
3
+ end
data/lib/hari.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'redis'
2
+ require 'redis/namespace'
3
+ require 'active_model'
4
+ require 'active_support/core_ext/hash/indifferent_access'
5
+ require 'active_support/core_ext/module/delegation'
6
+ require 'active_support/core_ext/object/try'
7
+ require 'yajl'
8
+
9
+ require 'hari/version'
10
+ require 'hari/configuration'
11
+ require 'hari/errors'
12
+ require 'hari/entity'
13
+ require 'hari/node'
14
+ require 'hari/relationship'
15
+
16
+ module Hari
17
+ extend self
18
+ extend Configuration
19
+
20
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Entity::Repository do
4
+
5
+ specify '.create, .find' do
6
+ model = TestModel.create(name: 'Ze', birth: '2012-04-20', points: '300')
7
+ model.id.should be
8
+
9
+ found = TestModel.find(model.id)
10
+ found.birth.year.should == 2012
11
+ found.birth.month.should == 4
12
+ found.birth.day.should == 20
13
+ found.points.should == 300
14
+ found.name.should == 'Ze'
15
+
16
+ model2 = TestModel.create(name: 'Jo', birth: '2009-03-21', points: '404')
17
+
18
+ founds = TestModel.find(model.id, model2.id)
19
+ founds.size.should == 2
20
+ end
21
+
22
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Entity::Serialization::Boolean do
4
+
5
+ describe '.serialize, .desserialize' do
6
+ it 'truthful values become true' do
7
+ subject.serialize(true).should be_true
8
+ subject.serialize('true').should be_true
9
+ subject.serialize('TRUE').should be_true
10
+ subject.serialize('1').should be_true
11
+ subject.serialize(1).should be_true
12
+ subject.serialize(1.0).should be_true
13
+ subject.serialize('x').should be_true
14
+ subject.serialize('X').should be_true
15
+ subject.serialize('t').should be_true
16
+ subject.serialize('T').should be_true
17
+ end
18
+
19
+ it 'untruthful values become false' do
20
+ subject.serialize(false).should be_false
21
+ subject.serialize('false').should be_false
22
+ subject.serialize('FALSE').should be_false
23
+ subject.serialize('0').should be_false
24
+ subject.serialize(0).should be_false
25
+ subject.serialize(0.0).should be_false
26
+ subject.serialize('').should be_false
27
+ subject.serialize(' ').should be_false
28
+ subject.serialize(nil).should be_false
29
+ end
30
+ end
31
+
32
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Entity::Serialization::Date do
4
+
5
+ describe '.serialize' do
6
+ it 'converts to date string' do
7
+ subject.serialize(Date.new(2011, 07, 01)).should == '2011-07-01'
8
+ end
9
+ end
10
+
11
+ describe '.desserialize' do
12
+ it 'converts to date' do
13
+ subject.desserialize('2011-07-01').should == Date.new(2011, 07, 01)
14
+ end
15
+
16
+ context 'when an invalid value is desserialized' do
17
+ it 'raises an error' do
18
+ expect { subject.desserialize('not a date') }.to raise_error
19
+ end
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Entity::Serialization::DateTime do
4
+
5
+ describe '.serialize' do
6
+ it 'converts to date time string' do
7
+ subject.serialize(DateTime.new(2011, 07, 01, 10, 20, 30)).should == '2011-07-01T10:20:30+00:00'
8
+ end
9
+ end
10
+
11
+ describe '.desserialize' do
12
+ it 'converts to date time' do
13
+ subject.desserialize('2011-07-01T10:20:30').should == DateTime.new(2011, 07, 01, 10, 20, 30)
14
+ end
15
+
16
+ context 'when an invalid value is desserialized' do
17
+ it 'raises an error' do
18
+ expect { subject.desserialize('not a date time') }.to raise_error
19
+ end
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Entity::Serialization::Float do
4
+
5
+ describe '.serialize, .desserialize' do
6
+ it 'converts to float' do
7
+ subject.serialize(4237.55).should == 4237.55
8
+ subject.serialize('4237.55').should == 4237.55
9
+ subject.serialize('4237').should == 4237.0
10
+ end
11
+
12
+ context 'when an invalid value is desserialized' do
13
+ it 'raises an error' do
14
+ expect { subject.desserialize('not a float') }.to raise_error
15
+ end
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Entity::Serialization::Integer do
4
+
5
+ describe '.serialize, .desserialize' do
6
+ it 'converts to integer' do
7
+ subject.serialize('1200').should == 1200
8
+ subject.serialize(1200).should == 1200
9
+ end
10
+
11
+ context 'when an invalid value is serialized' do
12
+ it 'raises an error' do
13
+ expect { subject.desserialize('not an integer') }.to raise_error
14
+ end
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Entity::Serialization::String do
4
+
5
+ describe '.serialize, .desserialize' do
6
+ it 'converts value to string' do
7
+ subject.serialize(:something).should == 'something'
8
+ subject.serialize(1).should == '1'
9
+ subject.serialize(nil).should == nil
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Entity::Serialization::Time do
4
+
5
+ describe '.serialize, .desserialize' do
6
+ it 'converts value to string' do
7
+ time = Time.new(2012, 04, 30, 12, 05, 50)
8
+ subject.serialize(time).should == '20120430120550'
9
+ subject.serialize('2012-04-30T12:05:50').should == '20120430120550'
10
+ subject.desserialize('20120430120550').should == time
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hari::Entity::Serialization do
4
+
5
+ describe '#to_json' do
6
+ it 'serializes instance to json' do
7
+ model = TestModel.new(name: 'Ze',
8
+ birth: Date.new(1986, 01, 23),
9
+ points: '200')
10
+
11
+ model.to_json.should == '{"id":null,"created_at":null,"updated_at":null,"name":"Ze","birth":"1986-01-23","points":200}'
12
+ end
13
+ end
14
+
15
+ describe '.from_json' do
16
+ it 'desserializes instance from json' do
17
+ model = TestModel.from_json('{"name":"Ze","birth":"1986-01-23","points":200}')
18
+ model.name.should == 'Ze'
19
+ model.birth.should == Date.new(1986, 01, 23)
20
+ model.points.should == 200
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,10 @@
1
+ $:.push '../lib'
2
+
3
+ require 'hari'
4
+ require 'pry'
5
+
6
+ class TestModel < Hari::Entity
7
+ property :name
8
+ property :birth, type: Date
9
+ property :points, type: Integer
10
+ end
metadata ADDED
@@ -0,0 +1,256 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hari
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Victor Rodrigues
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: redis
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: redis-namespace
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.2'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.2'
46
+ - !ruby/object:Gem::Dependency
47
+ name: hiredis
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '0.4'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.4'
62
+ - !ruby/object:Gem::Dependency
63
+ name: activemodel
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '3.2'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '3.2'
78
+ - !ruby/object:Gem::Dependency
79
+ name: activesupport
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '3.2'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '3.2'
94
+ - !ruby/object:Gem::Dependency
95
+ name: yajl-ruby
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: '1.1'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: '1.1'
110
+ - !ruby/object:Gem::Dependency
111
+ name: bundler
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: '1.3'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: '1.3'
126
+ - !ruby/object:Gem::Dependency
127
+ name: rspec
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ~>
132
+ - !ruby/object:Gem::Version
133
+ version: '2.13'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ~>
140
+ - !ruby/object:Gem::Version
141
+ version: '2.13'
142
+ - !ruby/object:Gem::Dependency
143
+ name: rake
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ~>
148
+ - !ruby/object:Gem::Version
149
+ version: '10.0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ~>
156
+ - !ruby/object:Gem::Version
157
+ version: '10.0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: pry
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ description: ! ' Hari is a graph library on top of Redis database + Lua scripts
175
+
176
+ '
177
+ email: victorc.rodrigues@gmail.com
178
+ executables: []
179
+ extensions: []
180
+ extra_rdoc_files: []
181
+ files:
182
+ - .gitignore
183
+ - Gemfile
184
+ - LICENSE
185
+ - README.md
186
+ - Rakefile
187
+ - hari.gemspec
188
+ - lib/hari.rb
189
+ - lib/hari/configuration.rb
190
+ - lib/hari/configuration/redis.rb
191
+ - lib/hari/entity.rb
192
+ - lib/hari/entity/property.rb
193
+ - lib/hari/entity/property/builder.rb
194
+ - lib/hari/entity/repository.rb
195
+ - lib/hari/entity/serialization.rb
196
+ - lib/hari/entity/serialization/boolean.rb
197
+ - lib/hari/entity/serialization/date.rb
198
+ - lib/hari/entity/serialization/datetime.rb
199
+ - lib/hari/entity/serialization/float.rb
200
+ - lib/hari/entity/serialization/integer.rb
201
+ - lib/hari/entity/serialization/string.rb
202
+ - lib/hari/entity/serialization/time.rb
203
+ - lib/hari/errors.rb
204
+ - lib/hari/node.rb
205
+ - lib/hari/node/queries.rb
206
+ - lib/hari/relationship.rb
207
+ - lib/hari/relationship/linked_list.rb
208
+ - lib/hari/relationship/sorted_set.rb
209
+ - lib/hari/scripts.rb
210
+ - lib/hari/version.rb
211
+ - spec/hari/entity/repository_spec.rb
212
+ - spec/hari/entity/serialization/boolean_spec.rb
213
+ - spec/hari/entity/serialization/date_spec.rb
214
+ - spec/hari/entity/serialization/datetime_spec.rb
215
+ - spec/hari/entity/serialization/float_spec.rb
216
+ - spec/hari/entity/serialization/integer_spec.rb
217
+ - spec/hari/entity/serialization/string_spec.rb
218
+ - spec/hari/entity/serialization/time_spec.rb
219
+ - spec/hari/entity/serialization_spec.rb
220
+ - spec/spec_helper.rb
221
+ homepage: http://github.com/rodrigues/hari
222
+ licenses:
223
+ - MIT
224
+ post_install_message:
225
+ rdoc_options: []
226
+ require_paths:
227
+ - lib
228
+ required_ruby_version: !ruby/object:Gem::Requirement
229
+ none: false
230
+ requirements:
231
+ - - ! '>='
232
+ - !ruby/object:Gem::Version
233
+ version: '0'
234
+ required_rubygems_version: !ruby/object:Gem::Requirement
235
+ none: false
236
+ requirements:
237
+ - - ! '>='
238
+ - !ruby/object:Gem::Version
239
+ version: '0'
240
+ requirements: []
241
+ rubyforge_project:
242
+ rubygems_version: 1.8.25
243
+ signing_key:
244
+ specification_version: 3
245
+ summary: Hari is a graph library on top of Redis + Lua scripts
246
+ test_files:
247
+ - spec/hari/entity/repository_spec.rb
248
+ - spec/hari/entity/serialization/boolean_spec.rb
249
+ - spec/hari/entity/serialization/date_spec.rb
250
+ - spec/hari/entity/serialization/datetime_spec.rb
251
+ - spec/hari/entity/serialization/float_spec.rb
252
+ - spec/hari/entity/serialization/integer_spec.rb
253
+ - spec/hari/entity/serialization/string_spec.rb
254
+ - spec/hari/entity/serialization/time_spec.rb
255
+ - spec/hari/entity/serialization_spec.rb
256
+ - spec/spec_helper.rb