restruct 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9a3ceeabf9eae0c207f69176f1f7933eb46068e6
4
+ data.tar.gz: c52480abf0ad9fe754617cc4b8c845e7b8e16e27
5
+ SHA512:
6
+ metadata.gz: dc9c0deaa324df308c8725e754e6195222a0d3749d7d436333c36451e394cadb2bca408bfdc3c00f730287cb46c4b2d12bbc4a0b68c1f3f13ef267fadf645648
7
+ data.tar.gz: 249265a027998c43c5ace27ec7f5bb1871960bae74ba73e50cd8a77ce4aa5c3dacea6b45d637060e99e8e672be11bf33da91f51e6aab8fa0228baeecfff05379
@@ -0,0 +1,2 @@
1
+ service_name: travis-ci
2
+ repo_token: mW2pXg2OXu39MNr3mg8HNDObqmiASx232
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
@@ -0,0 +1 @@
1
+ restruct
@@ -0,0 +1 @@
1
+ ruby 2.1
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0
5
+ - 2.1
6
+ - 2.2
7
+ - jruby
8
+ services:
9
+ - redis-server
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in restruct.gemspec
4
+ gemspec
5
+
6
+ gem 'coveralls', require: false
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Gabriel Naiman
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.
@@ -0,0 +1,40 @@
1
+ # Restruct
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/restruct.png)](https://rubygems.org/gems/restruct)
4
+ [![Build Status](https://travis-ci.org/gabynaiman/restruct.png?branch=master)](https://travis-ci.org/gabynaiman/restruct)
5
+ [![Coverage Status](https://coveralls.io/repos/gabynaiman/restruct/badge.png?branch=master)](https://coveralls.io/r/gabynaiman/restruct?branch=master)
6
+ [![Code Climate](https://codeclimate.com/github/gabynaiman/restruct.png)](https://codeclimate.com/github/gabynaiman/restruct)
7
+ [![Dependency Status](https://gemnasium.com/gabynaiman/restruct.png)](https://gemnasium.com/gabynaiman/restruct)
8
+
9
+ Redis structures
10
+
11
+ - Array
12
+ - Set
13
+ - Hash
14
+ - NestedHash
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ gem 'restruct'
21
+
22
+ And then execute:
23
+
24
+ $ bundle
25
+
26
+ Or install it yourself as:
27
+
28
+ $ gem install restruct
29
+
30
+ ## Usage
31
+
32
+ TODO: Write usage instructions here
33
+
34
+ ## Contributing
35
+
36
+ 1. Fork it ( https://github.com/gabynaiman/restruct/fork )
37
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
38
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
39
+ 4. Push to the branch (`git push origin my-new-feature`)
40
+ 5. Create a new Pull Request
@@ -0,0 +1,17 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:spec) do |t|
5
+ t.libs << 'spec'
6
+ t.pattern = 'spec/**/*_spec.rb'
7
+ t.verbose = false
8
+ end
9
+
10
+ task :console do
11
+ require 'pry'
12
+ require 'restruct'
13
+ ARGV.clear
14
+ Pry.start
15
+ end
16
+
17
+ task default: :spec
@@ -0,0 +1,30 @@
1
+ require 'redic'
2
+ require 'class_config'
3
+ require 'forwardable'
4
+ require 'securerandom'
5
+
6
+ require_relative 'restruct/version'
7
+ require_relative 'restruct/structure'
8
+ require_relative 'restruct/id'
9
+ require_relative 'restruct/array'
10
+ require_relative 'restruct/set'
11
+ require_relative 'restruct/hash'
12
+ require_relative 'restruct/nested_hash'
13
+ require_relative 'restruct/marshalizable'
14
+ require_relative 'restruct/marshal_array'
15
+ require_relative 'restruct/marshal_set'
16
+ require_relative 'restruct/marshal_hash'
17
+
18
+ module Restruct
19
+
20
+ extend ClassConfig
21
+
22
+ attr_config :redis, Redic.new
23
+ attr_config :id_separator, ':'
24
+ attr_config :id_generator, ->() { Id.new(:restruct)[SecureRandom.uuid] }
25
+
26
+ def self.generate_id
27
+ id_generator.call
28
+ end
29
+
30
+ end
@@ -0,0 +1,188 @@
1
+ module Restruct
2
+ class Array < Structure
3
+
4
+ include Enumerable
5
+ extend Forwardable
6
+
7
+ def_delegators :to_a, :uniq, :join, :reverse, :+, :-, :&, :|
8
+
9
+ def at(index)
10
+ deserialize redis.call('LINDEX', id, index)
11
+ end
12
+
13
+ def values_at(*args)
14
+ args.each_with_object([]) do |arg, array|
15
+ elements = self[arg]
16
+ array.push *(elements ? Array(elements) : [nil])
17
+ end
18
+ end
19
+
20
+ def fetch(index, default=nil, &block)
21
+ validate_index_type! index
22
+
23
+ if index < size
24
+ at index
25
+ else
26
+ validate_index_bounds! index if default.nil? && block.nil?
27
+ default || block.call(index)
28
+ end
29
+ end
30
+
31
+ def [](*args)
32
+ if args.count == 1
33
+ if args[0].is_a? Integer
34
+ at args[0].to_i
35
+ elsif args[0].is_a? Range
36
+ range args[0].first, args[0].last
37
+ else
38
+ validate_index_type! args.first
39
+ end
40
+ elsif args.count == 2
41
+ range args[0], args[0] + args[1] - 1
42
+ else
43
+ raise ArgumentError, "wrong number of arguments (#{args.count} for 1..2)"
44
+ end
45
+ end
46
+
47
+ def []=(index, element)
48
+ validate_index_type! index
49
+ validate_index_bounds! index
50
+
51
+ redis.call 'LSET', id, index, serialize(element)
52
+ end
53
+
54
+ def push(*elements)
55
+ redis.call 'RPUSH', id, *elements.map { |e| serialize e }
56
+ self
57
+ end
58
+ alias_method :<<, :push
59
+
60
+ def insert(index, *elements)
61
+ validate_index_type! index
62
+ tail_size = index >= 0 ? size - index : size - (size + index) - 1
63
+ tail = Array(pop(tail_size))
64
+ push *(elements + tail)
65
+ end
66
+
67
+ def concat(array)
68
+ push *array
69
+ end
70
+
71
+ def pop(count=1)
72
+ if count == 1
73
+ deserialize redis.call('RPOP', id)
74
+ else
75
+ [count, size].min.times.map { pop }.reverse
76
+ end
77
+ end
78
+
79
+ def shift(count=1)
80
+ if count == 1
81
+ deserialize redis.call('LPOP', id)
82
+ else
83
+ [count, size].min.times.map { shift }
84
+ end
85
+ end
86
+
87
+ def delete(element)
88
+ removed_count = redis.call 'LREM', id, 0, serialize(element)
89
+ removed_count > 0 ? element : nil
90
+ end
91
+
92
+ def delete_at(index)
93
+ validate_index_type! index
94
+ return nil if out_of_bounds? index
95
+
96
+ element = at index
97
+ tail_size = index >= 0 ? size - index : size - (size + index)
98
+ tail = Array(pop(tail_size))
99
+ push *tail[1..-1]
100
+ element
101
+ end
102
+
103
+ def delete_if
104
+ each { |e| delete e if yield e }
105
+ self
106
+ end
107
+
108
+ def keep_if
109
+ each { |e| delete e unless yield e }
110
+ self
111
+ end
112
+ alias_method :select!, :keep_if
113
+
114
+ def clear
115
+ destroy
116
+ self
117
+ end
118
+
119
+ def size
120
+ redis.call 'LLEN', id
121
+ end
122
+ alias_method :count, :size
123
+ alias_method :length, :size
124
+
125
+ def empty?
126
+ size == 0
127
+ end
128
+
129
+ def include?(element)
130
+ each { |e| return true if e == element }
131
+ false
132
+ end
133
+
134
+ def each
135
+ index = 0
136
+ while index < size
137
+ yield at(index), index
138
+ index += 1
139
+ end
140
+ end
141
+
142
+ def each_index
143
+ each { |_,i| yield i }
144
+ end
145
+
146
+ def first
147
+ at 0
148
+ end
149
+
150
+ def last
151
+ at -1
152
+ end
153
+
154
+ def to_a
155
+ range 0, -1
156
+ end
157
+ alias_method :to_ary, :to_a
158
+ alias_method :to_primitive, :to_a
159
+
160
+ private
161
+
162
+ def range(start, stop)
163
+ return nil if start > size
164
+ redis.call('LRANGE', id, start, stop).map { |e| deserialize e }
165
+ end
166
+
167
+ def validate_index_type!(index)
168
+ raise TypeError, "no implicit conversion from #{index.nil? ? 'nil' : index.class.name.downcase} to integer" unless index.is_a? Integer
169
+ end
170
+
171
+ def validate_index_bounds!(index)
172
+ raise IndexError, "index #{index} outside of array bounds: -#{size}...#{size}" if out_of_bounds? index
173
+ end
174
+
175
+ def out_of_bounds?(index)
176
+ !(-size..size).include?(index)
177
+ end
178
+
179
+ def serialize(string)
180
+ string
181
+ end
182
+
183
+ def deserialize(string)
184
+ string
185
+ end
186
+
187
+ end
188
+ end
@@ -0,0 +1,124 @@
1
+ module Restruct
2
+ class Hash < Structure
3
+
4
+ include Enumerable
5
+ extend Forwardable
6
+
7
+ def_delegators :to_h, :merge, :flatten, :invert
8
+
9
+ def [](key)
10
+ deserialize redis.call('HGET', id, key)
11
+ end
12
+
13
+ def fetch(key, default=nil, &block)
14
+ if key? key
15
+ self[key]
16
+ else
17
+ raise KeyError, "key not found: #{key}" if default.nil? && block.nil?
18
+ default || block.call(key)
19
+ end
20
+ end
21
+
22
+ def key(value)
23
+ index = values.index value
24
+ keys[index] if index
25
+ end
26
+
27
+ def store(key, value)
28
+ redis.call 'HSET', id, key, serialize(value)
29
+ value
30
+ end
31
+ alias_method :[]=, :store
32
+
33
+ def update(hash)
34
+ hash.each { |k,v| store k, v }
35
+ self
36
+ end
37
+ alias_method :merge!, :update
38
+
39
+ def delete(key)
40
+ value = self[key]
41
+ redis.call 'HDEL', id, key
42
+ value
43
+ end
44
+
45
+ def delete_if
46
+ each { |k,v| delete k if yield k, v }
47
+ self
48
+ end
49
+
50
+ def keep_if
51
+ each { |k,v| delete k unless yield k, v }
52
+ self
53
+ end
54
+ alias_method :select!, :keep_if
55
+
56
+ def clear
57
+ destroy
58
+ self
59
+ end
60
+
61
+ def keys
62
+ redis.call 'HKEYS', id
63
+ end
64
+
65
+ def values
66
+ redis.call('HVALS', id).map { |v| deserialize v }
67
+ end
68
+
69
+ def values_at(*keys)
70
+ keys.map { |k| self[k] }
71
+ end
72
+
73
+ def key?(key)
74
+ redis.call('HEXISTS', id, key) == 1
75
+ end
76
+ alias_method :has_key?, :key?
77
+
78
+ def value?(value)
79
+ values.include? value
80
+ end
81
+ alias_method :has_value?, :value?
82
+
83
+ def size
84
+ redis.call 'HLEN', id
85
+ end
86
+ alias_method :count, :size
87
+ alias_method :length, :size
88
+
89
+ def empty?
90
+ size == 0
91
+ end
92
+
93
+ def each
94
+ keys.each { |key| yield key, self[key] }
95
+ end
96
+ alias_method :each_pair, :each
97
+
98
+ def each_key
99
+ each { |k,v| yield k }
100
+ end
101
+
102
+ def each_value
103
+ each { |k,v| yield v }
104
+ end
105
+
106
+ def to_h
107
+ redis.call('HGETALL', id).each_slice(2).each_with_object({}) do |(k,v), hash|
108
+ hash[k] = deserialize v
109
+ end
110
+ end
111
+ alias_method :to_primitive, :to_h
112
+
113
+ private
114
+
115
+ def serialize(string)
116
+ string
117
+ end
118
+
119
+ def deserialize(string)
120
+ string
121
+ end
122
+
123
+ end
124
+ end