horcrux 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :dev do
6
+ gem 'rake'
7
+ gem 'msgpack'
8
+ end
9
+
data/horcrux.gemspec CHANGED
@@ -12,8 +12,8 @@ Gem::Specification.new do |s|
12
12
  ## If your rubyforge_project name is different, then edit it and comment out
13
13
  ## the sub! line in the Rakefile
14
14
  s.name = 'horcrux'
15
- s.version = '0.0.1'
16
- s.date = '2012-01-01'
15
+ s.version = '0.0.2'
16
+ s.date = '2012-01-03'
17
17
  s.rubyforge_project = 'horcrux'
18
18
 
19
19
  ## Make sure your summary is short. The description may be as long
@@ -40,12 +40,19 @@ Gem::Specification.new do |s|
40
40
  ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
41
41
  # = MANIFEST =
42
42
  s.files = %w[
43
+ Gemfile
43
44
  LICENSE.md
44
45
  README.md
45
46
  Rakefile
46
47
  horcrux.gemspec
47
48
  lib/horcrux.rb
49
+ lib/horcrux/entity.rb
50
+ lib/horcrux/serializers/gzip_serializer.rb
51
+ lib/horcrux/serializers/message_pack_serializer.rb
52
+ test/entity_test.rb
53
+ test/helper.rb
48
54
  test/memory_test.rb
55
+ test/serializer_test.rb
49
56
  ]
50
57
  # = MANIFEST =
51
58
 
@@ -0,0 +1,179 @@
1
+ require File.expand_path('../../horcrux', __FILE__)
2
+ require 'set'
3
+ require 'time'
4
+
5
+ module Horcrux
6
+ module Entity
7
+ def self.included(base)
8
+ class << base
9
+ attr_accessor :attributes, :writable_attributes, :default_attribute
10
+ end
11
+
12
+ base.attributes = Set.new
13
+ base.writable_attributes = Set.new
14
+ base.extend ClassMethods
15
+ end
16
+
17
+ module ClassMethods
18
+ # Public
19
+ def attr(type, *keys)
20
+ method = "build_#{type}_attr"
21
+ if respond_to?(method)
22
+ send method, keys, false
23
+ else
24
+ raise TypeError, "Type #{type.inspect} not recognized."
25
+ end
26
+ end
27
+
28
+ # Public
29
+ def readonly(type, *keys)
30
+ method = "build_#{type}_attr"
31
+ if respond_to?(method)
32
+ send method, keys, true
33
+ else
34
+ raise TypeError, "Type #{type.inspect} not recognized."
35
+ end
36
+ end
37
+
38
+ # Public
39
+ def from(hash = {})
40
+ hash.respond_to?(@default_attribute) ? hash : new(hash)
41
+ end
42
+
43
+ def build_string_attr(keys, is_readonly)
44
+ attr_reader *keys
45
+
46
+ build_attrs(keys, is_readonly) do |key_s|
47
+ ivar_key = "@#{key_s}"
48
+ define_method "#{key_s}=" do |value|
49
+ instance_variable_set ivar_key, value
50
+ end
51
+ end
52
+ end
53
+
54
+ def build_bool_attr(keys, is_readonly)
55
+ attr_reader *keys
56
+
57
+ build_attrs(keys, is_readonly) do |key_s|
58
+ ivar_key = "@#{key_s}"
59
+
60
+ define_method "#{key_s}?" do
61
+ !!instance_variable_get(ivar_key)
62
+ end
63
+
64
+ define_method "#{key_s}=" do |value|
65
+ instance_variable_set ivar_key, case value
66
+ when Fixnum then value > 0
67
+ when /t|f/i then value =~ /t/i ? true : false
68
+ else !!value
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ def build_array_attr(keys, is_readonly)
75
+ build_class_attr(Array, keys, is_readonly)
76
+ end
77
+
78
+ def build_hash_attr(keys, is_readonly)
79
+ build_class_attr(Hash, keys, is_readonly)
80
+ end
81
+
82
+ def build_time_attr(keys, is_readonly)
83
+ attr_reader *keys
84
+
85
+ build_attrs(keys, is_readonly) do |key_s|
86
+ ivar_key = "@#{key_s}"
87
+ define_method "#{key_s}=" do |value|
88
+ instance_variable_set ivar_key,
89
+ value.respond_to?(:utc) ?
90
+ value :
91
+ Time.at(value.to_i).utc
92
+ end
93
+ end
94
+ end
95
+
96
+ def build_class_attr(klass, keys, is_readonly)
97
+ build_attrs(keys, is_readonly) do |key_s|
98
+ ivar_key = "@#{key_s}"
99
+ define_method key_s do
100
+ instance_variable_get(ivar_key) ||
101
+ instance_variable_set(ivar_key, klass.new)
102
+ end
103
+
104
+ define_method "#{key_s}=" do |value|
105
+ unless value.is_a?(klass)
106
+ raise TypeError, "#{key_s} should be a #{klass}: #{value.inspect}"
107
+ end
108
+ instance_variable_set(ivar_key, value)
109
+ end
110
+ end
111
+ end
112
+
113
+ def build_attrs(keys, is_readonly)
114
+ keys.each do |key|
115
+ key_s = key.to_s
116
+ @default_attribute ||= key_s
117
+ @attributes << key_s
118
+ @writable_attributes << key_s unless is_readonly
119
+ yield key_s
120
+ end
121
+ end
122
+ end
123
+
124
+ # Public
125
+ def initialize(hash = {})
126
+ update_attrs(hash, all = true)
127
+ end
128
+
129
+ # Public: Updates multiple attributes.
130
+ #
131
+ # hash - A Hash containing valid attributes.
132
+ #
133
+ # Returns this Entity.
134
+ def update_attrs(hash, all = false)
135
+ attr = all ? self.class.attributes : self.class.writable_attributes
136
+ hash.each do |key, value|
137
+ key_s = key.to_s
138
+
139
+ if !attr.include?(key_s)
140
+ raise ArgumentError, "Invalid property: #{key.inspect}"
141
+ end
142
+
143
+ send "#{key_s}=", value
144
+ end
145
+
146
+ self
147
+ end
148
+
149
+ # Public
150
+ def each_attr(writable_only = false)
151
+ attr_method = writable_only ? :writable_attributes : :attributes
152
+ self.class.send(attr_method).each do |key|
153
+ if value = send(key)
154
+ yield key, value
155
+ end
156
+ end
157
+ self
158
+ end
159
+
160
+ # Public
161
+ def ==(other)
162
+ default_attr = self.class.default_attribute
163
+ other.class == self.class && other.send(default_attr) == send(default_attr)
164
+ end
165
+
166
+ # Public: Converts the valid attributes into a Hash of Symbol key and Object
167
+ # value.
168
+ #
169
+ # Returns a Hash.
170
+ def to_hash(writable_only = false)
171
+ hash = {}
172
+ each_attr(writable_only) do |key, value|
173
+ hash[key.to_sym] = value
174
+ end
175
+ hash
176
+ end
177
+ end
178
+ end
179
+
@@ -0,0 +1,29 @@
1
+ require File.expand_path('../../../horcrux', __FILE__)
2
+ require 'zlib'
3
+ require 'stringio'
4
+
5
+ module Horcrux
6
+ class GzipSerializer
7
+ def initialize(serializer)
8
+ @serializer = serializer
9
+ end
10
+
11
+ def dump(value)
12
+ s = StringIO.new
13
+ z = Zlib::GzipWriter.new(s)
14
+ z.write @serializer.dump(value)
15
+ s.string
16
+ ensure
17
+ z.close if z
18
+ end
19
+
20
+ def load(value)
21
+ s = StringIO.new(value)
22
+ z = Zlib::GzipReader.new(s)
23
+ @serializer.load(z.read)
24
+ ensure
25
+ z.close if z
26
+ end
27
+ end
28
+ end
29
+
@@ -0,0 +1,27 @@
1
+ require File.expand_path('../../../horcrux', __FILE__)
2
+ require 'msgpack'
3
+
4
+ module Horcrux
5
+ module MessagePackSerializer
6
+ extend self
7
+
8
+ def dump(value)
9
+ value.to_msgpack
10
+ end
11
+
12
+ def load(str)
13
+ MessagePack.unpack(str)
14
+ end
15
+ end
16
+ end
17
+
18
+ if Time.now.respond_to?(:to_msgpack)
19
+ raise LoadError, "Time#to_msgpack should not exist"
20
+ else
21
+ class Time
22
+ def to_msgpack(*args)
23
+ to_i.to_msgpack(*args)
24
+ end
25
+ end
26
+ end
27
+
data/lib/horcrux.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # See the README.md
2
2
  module Horcrux
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
 
5
5
  # Implements the optional methods of a Horcrux adapter.
6
6
  module Methods
@@ -0,0 +1,138 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ module Horcrux
4
+ class EntityTest < Test::Unit::TestCase
5
+ class Entity
6
+ include Horcrux::Entity
7
+
8
+ attr :string, :name
9
+ attr :bool, :admin
10
+ attr :array, :roles
11
+ attr :time, :updated_at
12
+
13
+ readonly :string, :type
14
+ readonly :hash, :codes
15
+ readonly :time, :created_at
16
+
17
+ def initialize(hash)
18
+ super(hash)
19
+ @created_at ||= Time.now.utc
20
+ end
21
+
22
+ def type
23
+ @type ||= 'default'
24
+ end
25
+ end
26
+
27
+ def test_accesses_attributes
28
+ ent = entity
29
+ assert_equal 'bob', ent.name
30
+ assert_equal 'person', ent.type
31
+ assert_equal true, ent.admin
32
+ assert ent.admin?
33
+
34
+ ent.name = 'bobby'
35
+ assert_equal 'bobby', ent.name
36
+
37
+ ent.admin = 0
38
+ assert !ent.admin?
39
+
40
+ ent.admin = 'true'
41
+ assert ent.admin?
42
+
43
+ ent.admin = false
44
+ assert !ent.admin?
45
+
46
+ ent.roles = %w(c)
47
+ assert_equal %w(c), ent.roles
48
+
49
+ assert_equal 2000, ent.created_at.year
50
+ assert_equal 2012, ent.updated_at.year
51
+
52
+ ent.updated_at = Time.utc 2010
53
+ assert_equal 2010, ent.updated_at.year
54
+
55
+ assert_raises ArgumentError do
56
+ ent.update_attrs :type => 'troll'
57
+ end
58
+
59
+ assert_raises ArgumentError do
60
+ ent.update_attrs :codes => 'troll'
61
+ end
62
+
63
+ assert_raises ArgumentError do
64
+ ent.update_attrs :created_at => Time.now
65
+ end
66
+
67
+ assert_raises TypeError do
68
+ ent.roles = 1
69
+ end
70
+ end
71
+
72
+ def test_initializes_with_default_value
73
+ ent = entity(:created_at => nil)
74
+ assert_equal Time.now.utc.year, ent.created_at.year
75
+ end
76
+
77
+ def test_dumps_entity_to_hash
78
+ hash = entity.to_hash
79
+ assert_equal 'bob', hash[:name]
80
+ assert_equal 'person', hash[:type]
81
+ assert_equal true, hash[:admin]
82
+ assert_equal %w(a b), hash[:roles]
83
+ assert_equal({"a" => 1, "b" => 2}, hash[:codes])
84
+ assert_equal 2000, hash[:created_at].year
85
+ assert_equal 2012, hash[:updated_at].year
86
+ end
87
+
88
+ def test_tracks_attributes
89
+ assert Entity.attributes.include?('name')
90
+ assert Entity.attributes.include?('admin')
91
+ assert Entity.attributes.include?('type')
92
+ assert Entity.attributes.include?('roles')
93
+ assert Entity.attributes.include?('codes')
94
+ assert Entity.attributes.include?('created_at')
95
+ assert Entity.attributes.include?('updated_at')
96
+ end
97
+
98
+ def test_tracks_writable_attributes
99
+ assert Entity.writable_attributes.include?('name')
100
+ assert Entity.writable_attributes.include?('admin')
101
+ assert Entity.writable_attributes.include?('roles')
102
+ assert Entity.writable_attributes.include?('updated_at')
103
+ assert !Entity.writable_attributes.include?('codes')
104
+ assert !Entity.writable_attributes.include?('type')
105
+ assert !Entity.writable_attributes.include?('created_at')
106
+ end
107
+
108
+ def test_tracks_default_attribute
109
+ assert_equal 'name', Entity.default_attribute
110
+ end
111
+
112
+ def test_convert_hash_to_entity
113
+ data = entity_data :name => "fred"
114
+ ent = entity :name => 'fred'
115
+ assert_equal ent, Entity.from(data)
116
+ assert_equal ent, Entity.from(ent)
117
+ end
118
+
119
+ def entity(options = {})
120
+ Entity.new(entity_data(options))
121
+ end
122
+
123
+ def entity_data(options = {})
124
+ hash = {:name => 'bob', :type => 'person', :admin => 't',
125
+ :created_at => Time.utc(2000), :updated_at => 1325619163,
126
+ :roles => %w(a b), :codes => {'a' => 1, 'b' => 2}}
127
+ options.each do |key, value|
128
+ if value.nil?
129
+ hash.delete key
130
+ else
131
+ hash[key] = value
132
+ end
133
+ end
134
+ hash
135
+ end
136
+ end
137
+ end
138
+
data/test/helper.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'test/unit'
2
+ require File.expand_path('../../lib/horcrux', __FILE__)
3
+ require File.expand_path('../../lib/horcrux/serializers/gzip_serializer', __FILE__)
4
+ require File.expand_path('../../lib/horcrux/entity', __FILE__)
5
+
data/test/memory_test.rb CHANGED
@@ -1,5 +1,4 @@
1
- require 'test/unit'
2
- require File.expand_path('../../lib/horcrux', __FILE__)
1
+ require File.expand_path('../helper', __FILE__)
3
2
 
4
3
  module Horcrux
5
4
  class MemoryTest < Test::Unit::TestCase
@@ -62,3 +61,4 @@ module Horcrux
62
61
  end
63
62
  end
64
63
  end
64
+
@@ -0,0 +1,40 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ module Horcrux
4
+ class SerializerTest < Test::Unit::TestCase
5
+ def test_null_serializer
6
+ assert_equal 1, NullSerializer.dump(1)
7
+ assert_equal 1, NullSerializer.load(1)
8
+ end
9
+
10
+ def test_string_serializer
11
+ assert_equal '1', StringSerializer.dump(1)
12
+ assert_equal '1', StringSerializer.load('1')
13
+ end
14
+
15
+ def test_gzip_serializer
16
+ data = '0' * 500
17
+ gzip = GzipSerializer.new(NullSerializer)
18
+ zipped = gzip.dump(data)
19
+ assert zipped.size < data.size
20
+ assert_equal data, gzip.load(zipped)
21
+ end
22
+
23
+ begin
24
+ require File.expand_path("../../lib/horcrux/serializers/message_pack_serializer", __FILE__)
25
+
26
+ def test_msgpack_serializer
27
+ hash = {:a => 1, :b => {:a => 'a'}, :c => Time.utc(2000)}
28
+
29
+ data = MessagePackSerializer.dump(hash)
30
+ loaded = MessagePackSerializer.load(data)
31
+ assert_equal 1, loaded['a']
32
+ assert_equal({"a" => "a"}, loaded["b"])
33
+ assert_equal 946684800, loaded['c']
34
+ end
35
+ rescue LoadError
36
+ puts "Skipping MessagePack test. run 'gem install msgpack'"
37
+ end
38
+ end
39
+ end
40
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: horcrux
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-01 00:00:00.000000000 Z
12
+ date: 2012-01-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: &70345353049180 !ruby/object:Gem::Requirement
16
+ requirement: &70123004569960 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70345353049180
24
+ version_requirements: *70123004569960
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: test-unit
27
- requirement: &70345353048680 !ruby/object:Gem::Requirement
27
+ requirement: &70123004569280 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,19 +32,26 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70345353048680
35
+ version_requirements: *70123004569280
36
36
  description: Simple key/value adapter library.
37
37
  email: technoweenie@gmail.com
38
38
  executables: []
39
39
  extensions: []
40
40
  extra_rdoc_files: []
41
41
  files:
42
+ - Gemfile
42
43
  - LICENSE.md
43
44
  - README.md
44
45
  - Rakefile
45
46
  - horcrux.gemspec
46
47
  - lib/horcrux.rb
48
+ - lib/horcrux/entity.rb
49
+ - lib/horcrux/serializers/gzip_serializer.rb
50
+ - lib/horcrux/serializers/message_pack_serializer.rb
51
+ - test/entity_test.rb
52
+ - test/helper.rb
47
53
  - test/memory_test.rb
54
+ - test/serializer_test.rb
48
55
  homepage: http://github.com/technoweenie/horcrux
49
56
  licenses: []
50
57
  post_install_message:
@@ -70,4 +77,7 @@ signing_key:
70
77
  specification_version: 2
71
78
  summary: Simple key/value adapter library.
72
79
  test_files:
80
+ - test/entity_test.rb
81
+ - test/helper.rb
73
82
  - test/memory_test.rb
83
+ - test/serializer_test.rb