sysarcana-data 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +11 -0
- data/Rakefile +11 -0
- data/lib/sysarcana/data.rb +26 -0
- data/lib/sysarcana/data/posts.rb +71 -0
- data/lib/sysarcana/data/redis_wrapper.rb +16 -0
- data/lib/sysarcana/data/version.rb +5 -0
- data/spec/post_spec.rb +138 -0
- data/sysarcana-data.gemspec +20 -0
- metadata +88 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'datalogger'
|
2
|
+
require 'hashie'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
require 'sysarcana/data/posts'
|
6
|
+
require 'sysarcana/data/redis_wrapper'
|
7
|
+
|
8
|
+
DataLogger::Logger.component = 'sysarcana'
|
9
|
+
|
10
|
+
module SysArcana
|
11
|
+
module Data
|
12
|
+
extend self
|
13
|
+
|
14
|
+
def connect_to_redis
|
15
|
+
DataLogger::Logger.log(action: 'Data.connect_to_redis') do
|
16
|
+
redis_url = ENV["REDISTOGO_URL"] || "redis://localhost:6379"
|
17
|
+
uri = URI.parse(redis_url)
|
18
|
+
RedisWrapper.new(:host => uri.host, :port => uri.port, :password => uri.password)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def redis
|
23
|
+
@redis ||= connect_to_redis
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module SysArcana
|
2
|
+
module Data
|
3
|
+
class Post < Hashie::Dash
|
4
|
+
extend DataLogger
|
5
|
+
include DataLogger
|
6
|
+
|
7
|
+
property :slug
|
8
|
+
property :title
|
9
|
+
property :body
|
10
|
+
property :published_at
|
11
|
+
|
12
|
+
def publish!
|
13
|
+
Post.publish!(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def save!
|
17
|
+
Post.save!(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.all
|
21
|
+
log(action: 'Post.all') do
|
22
|
+
all_slugs.map { |slug| find(slug) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.all_slugs
|
27
|
+
SysArcana::Data.redis.smembers("posts")
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.find(slug)
|
31
|
+
log(action: 'Post.find', slug: slug) do
|
32
|
+
result = SysArcana::Data.redis.hgetall("post:#{slug}")
|
33
|
+
if result == {}
|
34
|
+
log(action: 'Post.find', slug: slug, result: 'not-found')
|
35
|
+
nil
|
36
|
+
else
|
37
|
+
log(action: 'Post.find', slug: slug, result: 'found')
|
38
|
+
new(result)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.publish!(post)
|
44
|
+
log(action: 'Post.publish!', slug: post.slug) do
|
45
|
+
post.published_at = Time.now.utc.iso8601
|
46
|
+
post.save!
|
47
|
+
SysArcana::Data.redis.zadd "posts_published", post.published_at.to_i, post.slug
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.published
|
52
|
+
log(action: 'Post.published') do
|
53
|
+
published_slugs.map { |slug| find(slug) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.published_slugs
|
58
|
+
SysArcana::Data.redis.zrevrange("posts_published", 0, -1)
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.save!(post)
|
62
|
+
log(action: 'save!', slug: post.slug) do
|
63
|
+
SysArcana::Data.redis.multi do |r|
|
64
|
+
r.mapped_hmset "post:#{post.slug}", post
|
65
|
+
r.sadd "posts", post.slug
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'redis'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
class RedisWrapper < Redis
|
5
|
+
def nillify_string(s)
|
6
|
+
s.empty? ? nil : s
|
7
|
+
end
|
8
|
+
|
9
|
+
def normalize_hash(h)
|
10
|
+
h.inject({}) { |h, (k,v)| h[k] = nillify_string(v); h }
|
11
|
+
end
|
12
|
+
|
13
|
+
def hgetall(key)
|
14
|
+
normalize_hash(super)
|
15
|
+
end
|
16
|
+
end
|
data/spec/post_spec.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
|
4
|
+
require 'sysarcana/data'
|
5
|
+
|
6
|
+
include SysArcana::Data
|
7
|
+
|
8
|
+
describe Post do
|
9
|
+
before do
|
10
|
+
redis.flushdb
|
11
|
+
@post = Post.new
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "Post.new" do
|
15
|
+
it "must create a new Post object" do
|
16
|
+
@post.kind_of?(Post).must_equal(true)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "must respond to slug" do
|
20
|
+
@post.respond_to?(:slug).must_equal(true)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "must respond to title" do
|
24
|
+
@post.respond_to?(:title).must_equal(true)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "must respond to body" do
|
28
|
+
@post.respond_to?(:body).must_equal(true)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "must respond to published_at" do
|
32
|
+
@post.respond_to?(:published_at).must_equal(true)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "Post.all_slugs" do
|
37
|
+
it "must return an Array if there are not any" do
|
38
|
+
Post.all_slugs.kind_of?(Array).must_equal(true)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "must return an empty Array if there are not any slugs" do
|
42
|
+
Post.all_slugs.empty?.must_equal(true)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "must contain the slug if it has been saved" do
|
46
|
+
@post.slug = 'test'
|
47
|
+
@post.save!
|
48
|
+
Post.all_slugs.include?(@post.slug).must_equal(true)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "Post.all" do
|
53
|
+
it "must return an Array" do
|
54
|
+
Post.all.kind_of?(Array).must_equal(true)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "must reutrn an empty Array of there are not any posts" do
|
58
|
+
Post.all.empty?.must_equal(true)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "must contain the post if it has been saved" do
|
62
|
+
@post.slug = 'test'
|
63
|
+
@post.save!
|
64
|
+
Post.all.include?(@post).must_equal(true)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "save!" do
|
69
|
+
it "must create a post entry in redis" do
|
70
|
+
@post.slug = 'test'
|
71
|
+
@post.save!
|
72
|
+
redis.hgetall("post:#{@post.slug}").must_equal(@post.to_hash)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "must add the post to the posts_all set" do
|
76
|
+
@post.slug = 'test'
|
77
|
+
@post.save!
|
78
|
+
redis.sismember("posts", @post.slug).must_equal(true)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "publish!" do
|
83
|
+
before do
|
84
|
+
@post = Post.new slug: 'test'
|
85
|
+
@post.save!
|
86
|
+
end
|
87
|
+
|
88
|
+
it "must set the published_at attribute" do
|
89
|
+
@post.publish!
|
90
|
+
@post.published_at.wont_equal(nil)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "must add to the 'posts_published' sorted set" do
|
94
|
+
@post.publish!
|
95
|
+
redis.zrevrange('posts_published', 0, -1).include?(@post.slug).must_equal(true)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "published" do
|
100
|
+
before do
|
101
|
+
@post = Post.new slug: 'test'
|
102
|
+
@post.save!
|
103
|
+
end
|
104
|
+
|
105
|
+
it "must return an Array" do
|
106
|
+
Post.published.kind_of?(Array).must_equal(true)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "must be empty if there are not any published posts" do
|
110
|
+
Post.published.empty?.must_equal(true)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "must contain them if they exist" do
|
114
|
+
@post.publish!
|
115
|
+
Post.published.include?(@post).must_equal(true)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "published_slugs" do
|
120
|
+
before do
|
121
|
+
@post = Post.new slug: 'test'
|
122
|
+
@post.save!
|
123
|
+
end
|
124
|
+
|
125
|
+
it "must return an Array" do
|
126
|
+
Post.published_slugs.kind_of?(Array).must_equal(true)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "must be empty if there are not any slugs" do
|
130
|
+
Post.published_slugs.empty?.must_equal(true)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "must contain them if they are there" do
|
134
|
+
@post.publish!
|
135
|
+
Post.published_slugs.include?(@post.slug).must_equal(true)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/sysarcana/data/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Michael Gorsuch"]
|
6
|
+
gem.email = ["michael.gorsuch@gmail.com"]
|
7
|
+
gem.description = %q{data package for the SysArcana blog system}
|
8
|
+
gem.summary = %q{data package for the SysArcana blog system}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
gem.name = "sysarcana-data"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = SysArcana::Data::VERSION
|
17
|
+
gem.add_dependency('hashie')
|
18
|
+
gem.add_dependency('redis', '>= 2.2.2')
|
19
|
+
gem.add_dependency('datalogger', '0.0.5')
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sysarcana-data
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.14
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michael Gorsuch
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-28 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: hashie
|
16
|
+
requirement: &70189588943560 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70189588943560
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: redis
|
27
|
+
requirement: &70189588943060 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.2.2
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70189588943060
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: datalogger
|
38
|
+
requirement: &70189588942560 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - =
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.0.5
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70189588942560
|
47
|
+
description: data package for the SysArcana blog system
|
48
|
+
email:
|
49
|
+
- michael.gorsuch@gmail.com
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- .gitignore
|
55
|
+
- Gemfile
|
56
|
+
- Rakefile
|
57
|
+
- lib/sysarcana/data.rb
|
58
|
+
- lib/sysarcana/data/posts.rb
|
59
|
+
- lib/sysarcana/data/redis_wrapper.rb
|
60
|
+
- lib/sysarcana/data/version.rb
|
61
|
+
- spec/post_spec.rb
|
62
|
+
- sysarcana-data.gemspec
|
63
|
+
homepage: ''
|
64
|
+
licenses: []
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ! '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.8.10
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: data package for the SysArcana blog system
|
87
|
+
test_files:
|
88
|
+
- spec/post_spec.rb
|