hari 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +15 -0
  2. data/.travis.yml +15 -0
  3. data/LICENSE +15 -19
  4. data/README.md +22 -0
  5. data/hari.gemspec +2 -1
  6. data/lib/hari.rb +56 -1
  7. data/lib/hari/entity.rb +8 -11
  8. data/lib/hari/entity/property.rb +2 -2
  9. data/lib/hari/entity/property/builder.rb +9 -1
  10. data/lib/hari/entity/repository.rb +3 -2
  11. data/lib/hari/entity/serialization/float.rb +2 -0
  12. data/lib/hari/entity/serialization/integer.rb +3 -10
  13. data/lib/hari/node.rb +20 -3
  14. data/lib/hari/node/queries.rb +33 -0
  15. data/lib/hari/node/queries/list.rb +147 -0
  16. data/lib/hari/node/queries/relation.rb +100 -0
  17. data/lib/hari/node/queries/relation/backend/list.rb +35 -0
  18. data/lib/hari/node/queries/relation/backend/sorted_set.rb +95 -0
  19. data/lib/hari/node/queries/relation/runnable.rb +24 -0
  20. data/lib/hari/node/queries/relation/start.rb +19 -0
  21. data/lib/hari/node/queries/relation/step.rb +17 -0
  22. data/lib/hari/node/queries/set.rb +116 -0
  23. data/lib/hari/node/queries/sorted_set.rb +130 -0
  24. data/lib/hari/node/repository.rb +24 -0
  25. data/lib/hari/node/serialization.rb +24 -0
  26. data/lib/hari/relation.rb +72 -0
  27. data/lib/hari/relation/linked_list.rb +16 -0
  28. data/lib/hari/relation/sorted_set.rb +16 -0
  29. data/lib/hari/version.rb +1 -1
  30. data/spec/hari/configuration_spec.rb +5 -0
  31. data/spec/hari/entity/repository_spec.rb +4 -4
  32. data/spec/hari/entity/serialization_spec.rb +2 -2
  33. data/spec/hari/node/lists_spec.rb +126 -0
  34. data/spec/hari/node/sets_spec.rb +85 -0
  35. data/spec/hari/node/sorted_sets_spec.rb +89 -0
  36. data/spec/hari/node_spec.rb +79 -0
  37. data/spec/hari_spec.rb +37 -0
  38. data/spec/spec_helper.rb +11 -1
  39. metadata +48 -32
  40. data/lib/hari/relationship.rb +0 -72
  41. data/lib/hari/relationship/linked_list.rb +0 -22
  42. data/lib/hari/relationship/sorted_set.rb +0 -22
  43. data/lib/hari/scripts.rb +0 -26
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MDFjMThhM2VkNGMwNTRlYTMzNDM2Y2UyN2E5MDZhOTYxZDViZWI3MQ==
5
+ data.tar.gz: !binary |-
6
+ NTM0ZDBmNmJkYjMwOGZiNGRiZWE0MDg3NjYzZjIzZjBlNWY3YWI2Nw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MTA3OTM4MTkxN2E3MWM0YjRkNjBkYjNhNzc1OWIxMjZhMzU2NTJlYmZlNjRl
10
+ NmZmOTZkZjY3Yzk4ZTY3Zjk3NzRiMjJkMjdlMTNjNDgyZGFiZGQ1ZGY2YmQw
11
+ ZmZiN2JkZmEzYzkwZDI3Y2M4YzQ1NDlmZTExOTM0ODY0N2NlMDQ=
12
+ data.tar.gz: !binary |-
13
+ ZDBlNjJiYTg3NWRiMzU5YTkzNDRiNzRlOGE3MDFhYzI3ZDI0YWI4M2UzZDkx
14
+ NjljYTE1ODUwZjlkODIxZjc5Y2E4N2Q1ZjU0OGYxMTM4MDgxYzRlMTZiZDEw
15
+ ZWY2ZDIyNmIwYjU5NjRjMDI5ZjQyYWM5MTZhZDQ2YmJiZWQxNDg=
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3-p429
4
+ - 2.0.0-p195
5
+ before_install:
6
+ - "gem install bundler --no-rdoc --no-ri 1>/dev/null"
7
+ after_failure: sudo cat /var/log/redis/redis.log
8
+ script:
9
+ - "rspec spec"
10
+ notifications:
11
+ email: false
12
+ campfire:
13
+ secure: "COyR7y6VhbUK1MZwy75GksEJcsIASweKbKwwADIL45rI1df7H6op8ee+8G6o\nqBx5a9g7JGkWxAIHb2ML+lCDGe4zniruZdpljI+l+6XSKlkhGip3+4uszYEC\nkSyc3PyYQj7liREnMzwQ8VyH6y60hyfcfF5VtNEF13IWYoYa7WY="
14
+ services:
15
+ - redis-server
data/LICENSE CHANGED
@@ -1,22 +1,18 @@
1
- Copyright (c) 2013 Victor Rodrigues
1
+ Copyright (c) 2013, Clubjudge
2
+ All rights reserved.
2
3
 
3
- MIT License
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
5
 
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:
6
+ - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+ - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the docume
8
+ ntation and/or other materials provided with the distribution.
9
+ - Neither the name of the Clubjudge nor the names of its contributors may be used to endorse or promote products derived from this
10
+ software without specific prior written permission.
12
11
 
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.
12
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUD
13
+ ING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN N
14
+ O EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR C
15
+ ONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR P
16
+ ROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
17
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBI
18
+ LITY OF SUCH DAMAGE.
data/README.md CHANGED
@@ -0,0 +1,22 @@
1
+ [![Build Status](https://travis-ci.org/Clubjudge/hari.png?branch=master)](https://travis-ci.org/Clubjudge/hari)
2
+
3
+ ## hari
4
+
5
+ Hari is a library to persist and get nodes and its relations in Redis, using different data structures depending on your need.
6
+
7
+ Hari(user: 23).out(:follow).out(:activity).limit(25)
8
+
9
+ The query above will return the top `25` activities from all nodes user `23` follows.
10
+
11
+ ### Relations
12
+
13
+ Creating a relation can be as simple as:
14
+
15
+ Hari.relation! :follow, user, event
16
+
17
+ # where user / event are:
18
+
19
+ - objects with #id method (node representation will be class#id, like user#23)
20
+ - strings with node_type#node_id
21
+ - hash like { node_type => node_id }
22
+ - a Hari::Node instance
data/hari.gemspec CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
15
15
 
16
16
  s.author = 'Victor Rodrigues'
17
17
  s.email = 'victorc.rodrigues@gmail.com'
18
- s.homepage = 'http://github.com/rodrigues/hari'
18
+ s.homepage = 'http://github.com/Clubjudge/hari'
19
19
 
20
20
  s.license = 'MIT'
21
21
 
@@ -35,4 +35,5 @@ Gem::Specification.new do |s|
35
35
  s.add_development_dependency 'rspec', '~> 2.13'
36
36
  s.add_development_dependency 'rake', '~> 10.0'
37
37
  s.add_development_dependency 'pry'
38
+ s.add_development_dependency 'delorean'
38
39
  end
data/lib/hari.rb CHANGED
@@ -4,17 +4,72 @@ require 'active_model'
4
4
  require 'active_support/core_ext/hash/indifferent_access'
5
5
  require 'active_support/core_ext/module/delegation'
6
6
  require 'active_support/core_ext/object/try'
7
+ require 'active_support/core_ext/string/inflections'
7
8
  require 'yajl'
9
+ require 'erb'
10
+ require 'ostruct'
8
11
 
9
12
  require 'hari/version'
10
13
  require 'hari/configuration'
11
14
  require 'hari/errors'
12
15
  require 'hari/entity'
13
16
  require 'hari/node'
14
- require 'hari/relationship'
17
+ require 'hari/relation'
15
18
 
16
19
  module Hari
17
20
  extend self
18
21
  extend Configuration
22
+ extend Hari::Node::Queries
19
23
 
24
+ def node(arg)
25
+ type, id = node_type(arg), node_id(arg)
26
+ node = Node.new(model_id: id)
27
+ node.instance_variable_set '@node_type', type.to_s
28
+ node
29
+ end
30
+
31
+ def node_key(model)
32
+ if type = node_type(model)
33
+ "#{type}##{node_id(model)}"
34
+ else
35
+ node_id model
36
+ end
37
+ end
38
+
39
+ def node_id(model)
40
+ case model
41
+ when ::String, ::Symbol
42
+ model.to_s.split('#').last
43
+ when ::Hash
44
+ model.first[1]
45
+ when Hari::Node
46
+ model.model_id
47
+ else
48
+ model.id
49
+ end
50
+ end
51
+
52
+ def node_type(model)
53
+ case model
54
+ when ::String, ::Symbol
55
+ model.to_s.split('#').first
56
+ when ::Hash
57
+ model.first[0]
58
+ when Hari::Node
59
+ model.node_type
60
+ when Hari::Entity
61
+ nil
62
+ else
63
+ model.class.to_s.underscore.split('/').last
64
+ end
65
+ end
66
+
67
+ def relation!(type, from, target)
68
+ Relation.create type, from, target
69
+ end
70
+
71
+ end
72
+
73
+ def Hari(arg)
74
+ Hari.node arg
20
75
  end
data/lib/hari/entity.rb CHANGED
@@ -33,26 +33,23 @@ module Hari
33
33
  end
34
34
  end
35
35
 
36
- alias attribute send
37
- alias read_attribute send
36
+ alias :attribute :send
37
+ alias :read_attribute :send
38
+ alias :has_attribute? :respond_to?
38
39
 
39
40
  def write_attribute(name, value)
40
41
  send "#{name}=", value
41
42
  end
42
43
 
43
- def has_attribute?(name)
44
- respond_to? name
45
- end
46
-
47
44
  def ==(other)
48
- other.is_a?(Hari::Entity) && self.id == other.id
45
+ other.is_a?(Hari::Entity) && id == other.id
49
46
  end
50
47
 
51
48
  def new?
52
- self.id.nil?
49
+ id.nil?
53
50
  end
54
51
 
55
- alias new_record? new?
52
+ alias :new_record? :new?
56
53
 
57
54
  def persisted?
58
55
  not new?
@@ -63,14 +60,14 @@ module Hari
63
60
  end
64
61
 
65
62
  def generate_id
66
- 'ent' + ::Time.now.strftime('%Y%m%d%H%M%S') + SecureRandom.hex(3)
63
+ '_e' + ::Time.now.strftime('%Y%m%d%H%M%S') + SecureRandom.hex(3)
67
64
  end
68
65
 
69
66
  def to_s
70
67
  attrs = attributes
71
68
  attrs.delete 'id'
72
69
 
73
- "<#{self.class} id=#{id} attributes=#{attrs}>"
70
+ "<#{self.class} id='#{id}' attributes=#{attrs}>"
74
71
  end
75
72
 
76
73
  end
@@ -12,11 +12,11 @@ module Hari
12
12
  end
13
13
 
14
14
  def serialize(value)
15
- serializer.serialize(value, name: name)
15
+ serializer.serialize value, name: name
16
16
  end
17
17
 
18
18
  def desserialize(value)
19
- serializer.desserialize(value, name: name)
19
+ serializer.desserialize value, name: name
20
20
  end
21
21
 
22
22
  end
@@ -15,7 +15,15 @@ module Hari
15
15
  args.each { |name| property name, options }
16
16
 
17
17
  @properties ||= begin
18
- self == Hari::Entity ? [] : Hari::Entity.properties.dup
18
+ if self == Hari::Entity
19
+ []
20
+ else
21
+ entities_ancestors = ancestors.select do |a|
22
+ a.ancestors.include? Hari::Entity
23
+ end
24
+
25
+ entities_ancestors[1].properties.dup # the closest
26
+ end
19
27
  end
20
28
  end
21
29
 
@@ -7,7 +7,7 @@ module Hari
7
7
  run_callbacks(:save) { new? ? create : update }
8
8
  end
9
9
 
10
- alias save create_or_update
10
+ alias :save :create_or_update
11
11
 
12
12
  def create
13
13
  run_callbacks :create do
@@ -46,7 +46,7 @@ module Hari
46
46
  self
47
47
  end
48
48
 
49
- alias destroy delete
49
+ alias :destroy :delete
50
50
 
51
51
  module ClassMethods
52
52
 
@@ -57,6 +57,7 @@ module Hari
57
57
  def find(*args)
58
58
  options = args.extract_options!
59
59
  args.flatten!
60
+ args = args.map { |a| a.to_s.gsub(/^hari\:/, '') }
60
61
  args.one? ? find_one(args[0], options) : find_many(args, options)
61
62
  end
62
63
 
@@ -8,6 +8,8 @@ module Hari
8
8
  end
9
9
 
10
10
  def self.desserialize(value, options = {})
11
+ return unless value
12
+
11
13
  Float value
12
14
  rescue
13
15
  raise SerializationError, "#{options[:name]}:#{value} is not a float"
@@ -8,16 +8,9 @@ module Hari
8
8
  end
9
9
 
10
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
11
+ return unless value
12
+
13
+ Integer value
21
14
  rescue
22
15
  raise SerializationError, "#{options[:name]}:#{value} is not an integer"
23
16
  end
data/lib/hari/node.rb CHANGED
@@ -1,15 +1,32 @@
1
+ require 'hari/node/repository'
1
2
  require 'hari/node/queries'
3
+ require 'hari/node/serialization'
2
4
 
3
5
  module Hari
4
6
  class Node < Entity
5
7
  include Hari::Node::Queries
8
+ include Hari::Node::Repository
9
+ extend Hari::Node::Serialization
6
10
 
7
- property :model_id, required: true
11
+ property :model_id
12
+
13
+ def initialize(attrs = {})
14
+ attrs = { model_id: attrs } if attrs.kind_of?(::Fixnum)
15
+ super
16
+ end
8
17
 
9
18
  def generate_id
10
- return model_id if model_id.include?('#')
19
+ return super unless model_id
20
+
21
+ model_id.to_s.include?('#') ? model_id.to_s : "#{node_type}##{model_id}"
22
+ end
23
+
24
+ def node_type
25
+ @node_type || self.class.node_type
26
+ end
11
27
 
12
- self.class.to_s.underscore + "#" + model_id.to_s
28
+ def self.node_type
29
+ self.to_s.underscore
13
30
  end
14
31
 
15
32
  end
@@ -1,7 +1,40 @@
1
+ require 'hari/node/queries/list'
2
+ require 'hari/node/queries/set'
3
+ require 'hari/node/queries/sorted_set'
4
+ require 'hari/node/queries/relation'
5
+
1
6
  module Hari
2
7
  class Node < Entity
3
8
  module Queries
4
9
 
10
+ delegate :in, :out, to: :relation_query
11
+
12
+ delegate :set, :set!, to: :set_query
13
+ delegate :sorted_set, :sorted_set!, to: :sorted_set_query
14
+ delegate :list, :list!, to: :list_query
15
+
16
+ private
17
+
18
+ def set_query
19
+ Queries::Set.new query_node
20
+ end
21
+
22
+ def sorted_set_query
23
+ Queries::SortedSet.new query_node
24
+ end
25
+
26
+ def list_query
27
+ Queries::List.new query_node
28
+ end
29
+
30
+ def relation_query
31
+ Queries::Relation::Start.new query_node
32
+ end
33
+
34
+ def query_node
35
+ self.kind_of?(Hari::Node) ? self : nil
36
+ end
37
+
5
38
  end
6
39
  end
7
40
  end
@@ -0,0 +1,147 @@
1
+ module Hari
2
+ class Node < Entity
3
+ module Queries
4
+ class List
5
+
6
+ attr_reader :node, :name
7
+
8
+ def initialize(node = nil)
9
+ @node = node
10
+ end
11
+
12
+ def key
13
+ @key ||= begin
14
+ prefix = node ? "#{Hari.node_key(node)}:" : ''
15
+ prefix + name.to_s
16
+ end
17
+ end
18
+
19
+ def list(name)
20
+ @name = name
21
+ self
22
+ end
23
+
24
+ def list!(name)
25
+ @name = name
26
+ range
27
+ end
28
+
29
+ def [](*args)
30
+ arg = args.first
31
+
32
+ if args.size == 2
33
+ range *args
34
+ elsif arg.kind_of? Integer
35
+ at arg
36
+ elsif arg.kind_of? Range
37
+ range arg.first, arg.last
38
+ end
39
+ end
40
+
41
+ def first
42
+ self[0]
43
+ end
44
+
45
+ def last
46
+ self[-1]
47
+ end
48
+
49
+ def []=(index, member)
50
+ Hari.redis.lset key, index, member
51
+ end
52
+
53
+ def range(start = 0, stop = -1)
54
+ Hari.redis.lrange key, start, stop
55
+ end
56
+
57
+ alias :members :range
58
+ alias :to_a :range
59
+
60
+ def from(index)
61
+ range index
62
+ end
63
+
64
+ def to(index)
65
+ range 0, index
66
+ end
67
+
68
+ def at(index)
69
+ Hari.redis.lindex key, index
70
+ end
71
+
72
+ alias :index :at
73
+
74
+ def trim(start, stop)
75
+ Hari.redis.ltrim key, start, stop
76
+ end
77
+
78
+ def count
79
+ Hari.redis.llen key
80
+ end
81
+
82
+ alias :size :count
83
+ alias :length :count
84
+
85
+ def empty?
86
+ count == 0
87
+ end
88
+
89
+ def one?
90
+ count == 1
91
+ end
92
+
93
+ def many?
94
+ count > 1
95
+ end
96
+
97
+ def include?(member)
98
+ range.include? member
99
+ end
100
+
101
+ alias :member? :include?
102
+
103
+ def push(*members)
104
+ Hari.redis.rpush key, members
105
+ end
106
+
107
+ alias :rpush :push
108
+ alias :add :push
109
+
110
+ def lpush(*members)
111
+ Hari.redis.lpush key, members
112
+ end
113
+
114
+ def <<(member)
115
+ push member
116
+ end
117
+
118
+ def insert_before(pivot, member)
119
+ Hari.redis.linsert key, :before, pivot, member
120
+ end
121
+
122
+ def insert_after(pivot, member)
123
+ Hari.redis.linsert key, :after, pivot, member
124
+ end
125
+
126
+ alias :insert :insert_after
127
+
128
+ def delete(member, count = 0)
129
+ Hari.redis.lrem key, count, member
130
+ end
131
+
132
+ def pop
133
+ Hari.redis.rpop key
134
+ end
135
+
136
+ alias :rpop :pop
137
+
138
+ def shift
139
+ Hari.redis.lpop key
140
+ end
141
+
142
+ alias :lpop :shift
143
+
144
+ end
145
+ end
146
+ end
147
+ end