hari 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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