pigeon_hole 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/pigeon_hole/json_date.rb +29 -0
- data/lib/pigeon_hole/json_date_time.rb +41 -0
- data/lib/pigeon_hole/json_symbol.rb +22 -0
- data/lib/pigeon_hole/json_time.rb +34 -0
- data/lib/pigeon_hole/typed_json.rb +40 -0
- data/lib/pigeon_hole.rb +19 -0
- data/spec/integration_spec.rb +99 -0
- data/spec/spec_helper.rb +33 -0
- metadata +54 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9f679f4b70108c6d3d567f1905462749de53dd26
|
4
|
+
data.tar.gz: c98c767931a8f0e1799e7db0d743c484ac46abf7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7fa933c8432ae976cc51a96f9ca01355d9ccdece601844411207752f629cb5a31fc89337827c91944426dd5b2e971d1351e44131185f09bc046eeedc00ca9e49
|
7
|
+
data.tar.gz: d3384729d4a8a7bdd0cf82a6099fea598fdfb62da7fea3e66dc7a4e0242c203b43e9db9539aaf721c101bebd4124a2088acc14f66d9efe8cf4d7f8969d2149f6
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module PigeonHole
|
2
|
+
class JSONDate < SimpleDelegator
|
3
|
+
# Deserializes JSON string by converting Julian year <tt>y</tt>, month
|
4
|
+
# <tt>m</tt>, day <tt>d</tt> and Day of Calendar Reform <tt>sg</tt> to Date.
|
5
|
+
def self.json_create(object)
|
6
|
+
Date.civil(*object.values_at('y', 'm', 'd', 'sg'))
|
7
|
+
end
|
8
|
+
|
9
|
+
#alias start sg unless method_defined?(:start)
|
10
|
+
|
11
|
+
# Returns a hash, that will be turned into a JSON object and represent this
|
12
|
+
# object.
|
13
|
+
def as_json(*)
|
14
|
+
{
|
15
|
+
JSON.create_id => self.class.name,
|
16
|
+
'y' => year,
|
17
|
+
'm' => month,
|
18
|
+
'd' => day,
|
19
|
+
'sg' => start,
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
# Stores class name (Date) with Julian year <tt>y</tt>, month <tt>m</tt>, day
|
24
|
+
# <tt>d</tt> and Day of Calendar Reform <tt>sg</tt> as JSON string
|
25
|
+
def to_json(*args)
|
26
|
+
as_json.to_json(*args)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module PigeonHole
|
2
|
+
class JSONDateTime < SimpleDelegator
|
3
|
+
# Deserializes JSON string by converting year <tt>y</tt>, month <tt>m</tt>,
|
4
|
+
# day <tt>d</tt>, hour <tt>H</tt>, minute <tt>M</tt>, second <tt>S</tt>,
|
5
|
+
# offset <tt>of</tt> and Day of Calendar Reform <tt>sg</tt> to DateTime.
|
6
|
+
def self.json_create(object)
|
7
|
+
args = object.values_at('y', 'm', 'd', 'H', 'M', 'S')
|
8
|
+
of_a, of_b = object['of'].split('/')
|
9
|
+
if of_b and of_b != '0'
|
10
|
+
args << DateTime.send(:Rational, of_a.to_i, of_b.to_i)
|
11
|
+
else
|
12
|
+
args << of_a
|
13
|
+
end
|
14
|
+
args << object['sg']
|
15
|
+
DateTime.civil(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns a hash, that will be turned into a JSON object and represent this
|
19
|
+
# object.
|
20
|
+
def as_json(*)
|
21
|
+
{
|
22
|
+
JSON.create_id => self.class.name,
|
23
|
+
'y' => year,
|
24
|
+
'm' => month,
|
25
|
+
'd' => day,
|
26
|
+
'H' => hour,
|
27
|
+
'M' => min,
|
28
|
+
'S' => sec,
|
29
|
+
'of' => offset.to_s,
|
30
|
+
'sg' => start,
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
# Stores class name (DateTime) with Julian year <tt>y</tt>, month <tt>m</tt>,
|
35
|
+
# day <tt>d</tt>, hour <tt>H</tt>, minute <tt>M</tt>, second <tt>S</tt>,
|
36
|
+
# offset <tt>of</tt> and Day of Calendar Reform <tt>sg</tt> as JSON string
|
37
|
+
def to_json(*args)
|
38
|
+
as_json.to_json(*args)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module PigeonHole
|
2
|
+
class JSONSymbol < SimpleDelegator
|
3
|
+
# Returns a hash, that will be turned into a JSON object and represent this
|
4
|
+
# object.
|
5
|
+
def as_json(*)
|
6
|
+
{
|
7
|
+
JSON.create_id => self.class.name,
|
8
|
+
's' => to_s,
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
# Stores class name (Symbol) with String representation of Symbol as a JSON string.
|
13
|
+
def to_json(*a)
|
14
|
+
as_json.to_json(*a)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Deserializes JSON string by converting the <tt>string</tt> value stored in the object to a Symbol
|
18
|
+
def self.json_create(o)
|
19
|
+
o['s'].to_sym
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module PigeonHole
|
2
|
+
class JSONTime < SimpleDelegator
|
3
|
+
# Deserializes JSON string by converting time since epoch to Time
|
4
|
+
def self.json_create(object)
|
5
|
+
if usec = object.delete('u') # used to be tv_usec -> tv_nsec
|
6
|
+
object['n'] = usec * 1000
|
7
|
+
end
|
8
|
+
if method_defined?(:tv_nsec)
|
9
|
+
Time.at(object['s'], Time.Rational(object['n'], 1000))
|
10
|
+
else
|
11
|
+
Time.at(object['s'], object['n'] / 1000)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns a hash, that will be turned into a JSON object and represent this
|
16
|
+
# object.
|
17
|
+
def as_json(*)
|
18
|
+
nanoseconds = [ tv_usec * 1000 ]
|
19
|
+
respond_to?(:tv_nsec) and nanoseconds << tv_nsec
|
20
|
+
nanoseconds = nanoseconds.max
|
21
|
+
{
|
22
|
+
JSON.create_id => self.class.name,
|
23
|
+
's' => tv_sec,
|
24
|
+
'n' => nanoseconds,
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
# Stores class name (Time) with number of seconds since epoch and number of
|
29
|
+
# microseconds for Time as JSON string
|
30
|
+
def to_json(*args)
|
31
|
+
as_json.to_json(*args)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module PigeonHole
|
4
|
+
class TypedJSON
|
5
|
+
def self.generate(obj, *args)
|
6
|
+
hash_dup = each_with_parent(obj)
|
7
|
+
JSON.generate(hash_dup, *args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.map_to_json(obj)
|
11
|
+
case obj
|
12
|
+
when Time
|
13
|
+
JSONTime.new(obj)
|
14
|
+
when DateTime
|
15
|
+
JSONDateTime.new(obj)
|
16
|
+
when Date
|
17
|
+
JSONDate.new(obj)
|
18
|
+
when Symbol
|
19
|
+
JSONSymbol.new(obj)
|
20
|
+
else
|
21
|
+
obj
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.each_with_parent(hash, result=nil)
|
26
|
+
duplicated_hash = {} || result
|
27
|
+
|
28
|
+
hash.each do |k, v|
|
29
|
+
case v
|
30
|
+
when Hash
|
31
|
+
duplicated_hash[k] = each_with_parent(v, duplicated_hash)
|
32
|
+
else
|
33
|
+
duplicated_hash[k] = map_to_json(v)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
duplicated_hash
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/pigeon_hole.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module PigeonHole
|
2
|
+
require_relative 'pigeon_hole/typed_json'
|
3
|
+
require_relative 'pigeon_hole/json_date'
|
4
|
+
require_relative 'pigeon_hole/json_date_time'
|
5
|
+
require_relative 'pigeon_hole/json_symbol'
|
6
|
+
require_relative 'pigeon_hole/json_time'
|
7
|
+
|
8
|
+
def self.generate(obj, *args)
|
9
|
+
TypedJSON.generate(obj, *args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.parse(string)
|
13
|
+
load(string)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.load(string)
|
17
|
+
JSON.load(string)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "serializing dates" do
|
4
|
+
let(:date) { random_date }
|
5
|
+
|
6
|
+
subject { PigeonHole.generate(date: date) }
|
7
|
+
|
8
|
+
it "serializes hash into a string" do
|
9
|
+
result = subject
|
10
|
+
expect(result).to_not be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it "can be deserialized to a date time" do
|
14
|
+
result = subject
|
15
|
+
hash = PigeonHole.parse(result)
|
16
|
+
expect(hash).to eq({ "date" => date })
|
17
|
+
expect(hash["date"]).to be_a(Date)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "serializing times" do
|
22
|
+
let(:time) { random_time }
|
23
|
+
|
24
|
+
subject { PigeonHole.generate(time: time) }
|
25
|
+
|
26
|
+
it "serializes hash into a string" do
|
27
|
+
result = subject
|
28
|
+
expect(result).to_not be_empty
|
29
|
+
end
|
30
|
+
|
31
|
+
it "can be deserialized to a time" do
|
32
|
+
result = subject
|
33
|
+
hash = PigeonHole.parse(result)
|
34
|
+
expect(hash).to eq({ "time" => time })
|
35
|
+
expect(hash["time"]).to be_a(Time)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "serializing datetimes" do
|
40
|
+
let(:date_time) { random_date_time }
|
41
|
+
|
42
|
+
subject { PigeonHole.generate(date_time: date_time) }
|
43
|
+
|
44
|
+
it "serializes hash into a string" do
|
45
|
+
result = subject
|
46
|
+
expect(result).to_not be_empty
|
47
|
+
end
|
48
|
+
|
49
|
+
it "can be deserialized to a date_time" do
|
50
|
+
result = subject
|
51
|
+
hash = PigeonHole.parse(result)
|
52
|
+
expect(hash["date_time"]).to be_a(DateTime)
|
53
|
+
expect(hash["date_time"].to_date).to eq(date_time.to_date)
|
54
|
+
expect(hash["date_time"].to_time.to_i).to eq(date_time.to_time.to_i)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "serializing symbols" do
|
59
|
+
let(:symbol) { :a_symbol }
|
60
|
+
|
61
|
+
subject { PigeonHole.generate(symbol: symbol) }
|
62
|
+
|
63
|
+
it "serializes hash into a string" do
|
64
|
+
result = subject
|
65
|
+
expect(result).to_not be_empty
|
66
|
+
end
|
67
|
+
|
68
|
+
it "can be deserialized to a symbol" do
|
69
|
+
result = subject
|
70
|
+
hash = PigeonHole.parse(result)
|
71
|
+
expect(hash).to eq({ "symbol" => symbol })
|
72
|
+
expect(hash["symbol"]).to be_a(Symbol)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "serializing nested hashes" do
|
77
|
+
let(:expected) do
|
78
|
+
{
|
79
|
+
foo: {
|
80
|
+
bar: random_time,
|
81
|
+
baz: :temp
|
82
|
+
}
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
subject { PigeonHole.generate(expected) }
|
87
|
+
|
88
|
+
it "serializes hash into a string" do
|
89
|
+
result = subject
|
90
|
+
expect(result).to_not be_empty
|
91
|
+
end
|
92
|
+
|
93
|
+
it "can be deserialized to a symbol" do
|
94
|
+
result = subject
|
95
|
+
hash = PigeonHole.parse(result)
|
96
|
+
|
97
|
+
expect(symbolize_hash(hash)).to eq(expected)
|
98
|
+
end
|
99
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rspec'
|
3
|
+
|
4
|
+
require "#{Rake.application.original_dir}/lib/pigeon_hole"
|
5
|
+
|
6
|
+
include PigeonHole
|
7
|
+
|
8
|
+
def random_integer
|
9
|
+
rand(9999)
|
10
|
+
end
|
11
|
+
|
12
|
+
def random_time
|
13
|
+
Time.now - random_integer
|
14
|
+
end
|
15
|
+
|
16
|
+
def random_date
|
17
|
+
Date.today - random_integer
|
18
|
+
end
|
19
|
+
|
20
|
+
def random_date_time
|
21
|
+
DateTime.now
|
22
|
+
end
|
23
|
+
|
24
|
+
def symbolize_hash(obj)
|
25
|
+
if obj.is_a?(Hash)
|
26
|
+
obj.inject({}) do |memo, (k,v)|
|
27
|
+
memo[k.to_sym] = symbolize_hash(v)
|
28
|
+
memo
|
29
|
+
end
|
30
|
+
else
|
31
|
+
obj
|
32
|
+
end
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pigeon_hole
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stephen Binns
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-07-13 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/pigeon_hole.rb
|
20
|
+
- lib/pigeon_hole/json_date.rb
|
21
|
+
- lib/pigeon_hole/json_date_time.rb
|
22
|
+
- lib/pigeon_hole/json_symbol.rb
|
23
|
+
- lib/pigeon_hole/json_time.rb
|
24
|
+
- lib/pigeon_hole/typed_json.rb
|
25
|
+
- spec/integration_spec.rb
|
26
|
+
- spec/spec_helper.rb
|
27
|
+
homepage: http://www.cronofy.com
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
metadata: {}
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubyforge_project:
|
47
|
+
rubygems_version: 2.6.1
|
48
|
+
signing_key:
|
49
|
+
specification_version: 4
|
50
|
+
summary: Opt-in typed serialization for complex JSON types
|
51
|
+
test_files:
|
52
|
+
- spec/integration_spec.rb
|
53
|
+
- spec/spec_helper.rb
|
54
|
+
has_rdoc:
|