ruson 1.3.0 → 1.3.5
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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.ruby-version +1 -0
- data/README.md +62 -11
- data/lib/ruson/base.rb +31 -11
- data/lib/ruson/class/array.rb +7 -0
- data/lib/ruson/class/boolean.rb +13 -11
- data/lib/ruson/class/float.rb +6 -4
- data/lib/ruson/class/integer.rb +6 -4
- data/lib/ruson/class/time.rb +12 -10
- data/lib/ruson/converter.rb +1 -1
- data/lib/ruson/json.rb +9 -0
- data/lib/ruson/persistence.rb +5 -11
- data/lib/ruson/querying.rb +66 -4
- data/lib/ruson/value.rb +0 -1
- data/lib/ruson/version.rb +1 -1
- data/ruson.gemspec +5 -4
- metadata +16 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed994824268107e491819721d5566eb742d97fc062179ca8f31e5e63c5886c22
|
4
|
+
data.tar.gz: '09e7b5315cc8612dec090b87b2d452db1c1c95338f4a6693ece851a6ba407ccb'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c8f9b71aa0c7ac63f93bd67ebc3e7b063c16ef118e6e67e846df6d8f445f3b6e0ef5c6a8a9638d0e6b421231afe7a2bc4c9345a0fc036650a7e3da027f446c7
|
7
|
+
data.tar.gz: 2202ca458dd9f29eba01e242e4b302dc8e1730a80eeb563bf036f4f7be01be52570c1a03550b1597ed3d71daf1e25e8fdffbdd1659b035dd6f636c08e7cac63d
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.5.0
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Ruson
|
2
2
|
|
3
|
-
|
3
|
+
A Ruby serialization/deserialization library to convert Ruby Objects into JSON and back
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -123,34 +123,42 @@ post.picture.url #=> 'http://sample.com/picture.png'
|
|
123
123
|
|
124
124
|
###### Primary classes
|
125
125
|
|
126
|
-
*
|
127
|
-
*
|
128
|
-
* Float
|
126
|
+
* Ruson::Array
|
127
|
+
* Ruson::Boolean
|
128
|
+
* Ruson::Float
|
129
|
+
* Ruson::Integer
|
130
|
+
* Ruson::Time
|
129
131
|
|
130
132
|
|
131
133
|
post.json
|
132
134
|
```json
|
133
135
|
{
|
134
136
|
"title": "Ruson",
|
137
|
+
"items": ["orange", "apple"],
|
135
138
|
"is_new": "true",
|
139
|
+
"rate": "3.8",
|
136
140
|
"view": "1234",
|
137
|
-
"
|
141
|
+
"expired_at": 1575608299
|
138
142
|
}
|
139
143
|
```
|
140
144
|
|
141
145
|
```ruby
|
142
146
|
class Post < Ruson::Base
|
143
147
|
field :title
|
144
|
-
field :
|
145
|
-
field :
|
146
|
-
field :rate, class: Float
|
148
|
+
field :items, class: Ruson::Array
|
149
|
+
field :is_new, class: Ruson::Boolean
|
150
|
+
field :rate, class: Ruson::Float
|
151
|
+
field :view, class: Ruson::Integer
|
152
|
+
field :expired_at, class: Ruson::Time
|
147
153
|
end
|
148
154
|
|
149
155
|
json = File.read('post.json')
|
150
156
|
post = Post.new(json)
|
157
|
+
post.items #=> ["orange", "apple"]
|
151
158
|
post.is_new #=> true
|
152
|
-
post.view #=> 1234
|
153
159
|
post.rate #=> 3.8
|
160
|
+
post.view #=> 1234
|
161
|
+
post.expired_at #=> 2019-12-06 04:58:19 +0000
|
154
162
|
```
|
155
163
|
|
156
164
|
##### each class
|
@@ -337,7 +345,50 @@ Ruson.output_folder = './db/'
|
|
337
345
|
#### Find a record by ID
|
338
346
|
|
339
347
|
```ruby
|
340
|
-
|
348
|
+
User.find(1) # Searches for a ./db/Users/1.json file
|
349
|
+
|
350
|
+
# Searching a user which doesn't exist
|
351
|
+
User.find(1234) #=> nil
|
352
|
+
User.find!(1234) #=> raises Ruson::RecordNotFound
|
353
|
+
```
|
354
|
+
|
355
|
+
#### Find first record
|
356
|
+
|
357
|
+
```ruby
|
358
|
+
User.first # Loads the first ./db/Users/*.json file.
|
359
|
+
|
360
|
+
# Without existing User records
|
361
|
+
User.first #=> nil
|
362
|
+
User.first! #=> raises Ruson::RecordNotFound
|
363
|
+
```
|
364
|
+
|
365
|
+
#### Find a record by attributes
|
366
|
+
|
367
|
+
post.json
|
368
|
+
|
369
|
+
```json
|
370
|
+
{
|
371
|
+
"title": "Ruson",
|
372
|
+
"content": "Welcome!"
|
373
|
+
}
|
374
|
+
```
|
375
|
+
|
376
|
+
```ruby
|
377
|
+
Post.create(File.read('post.json'))
|
378
|
+
```
|
379
|
+
|
380
|
+
```ruby
|
381
|
+
Post.where(title: 'Ruson')
|
382
|
+
#=> [#<Post:0x000055bb2e907b78 @title="Ruson", @content="Welcome!", @id=1>]
|
383
|
+
|
384
|
+
Post.where(content: 'Wel')
|
385
|
+
#=> []
|
386
|
+
|
387
|
+
Post.where(content: 'Welcome!')
|
388
|
+
#=> [#<Post:0x000055bb2e907b78 @title="Ruson", @content="Welcome!", @id=1>]
|
389
|
+
|
390
|
+
Post.where(title: 'Ruson', content: 'Welcome!')
|
391
|
+
#=> [#<Post:0x000055bb2e907b78 @title="Ruson", @content="Welcome!", @id=1>]
|
341
392
|
```
|
342
393
|
|
343
394
|
## Development
|
@@ -366,7 +417,7 @@ rake install:local # Build and install ruson-1.2.0.gem into system gems witho
|
|
366
417
|
rake release[remote] # Create tag v1.2.0 and build and push ruson-1.2.0.gem to rubygems.org
|
367
418
|
rake spec # Run RSpec code examples
|
368
419
|
```
|
369
|
-
_`--rm` means delete the container after the command ended._
|
420
|
+
_`--rm` means delete the container after the command has ended._
|
370
421
|
|
371
422
|
In order to execute the tests:
|
372
423
|
|
data/lib/ruson/base.rb
CHANGED
@@ -2,6 +2,7 @@ require 'json'
|
|
2
2
|
require 'active_support'
|
3
3
|
require 'active_support/core_ext'
|
4
4
|
|
5
|
+
require 'ruson/class/array'
|
5
6
|
require 'ruson/class/boolean'
|
6
7
|
require 'ruson/class/float'
|
7
8
|
require 'ruson/class/integer'
|
@@ -58,6 +59,7 @@ module Ruson
|
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
62
|
+
# ~~~~ Mixins ~~~~
|
61
63
|
include Ruson::Converter
|
62
64
|
include Ruson::Json
|
63
65
|
include Ruson::Nilable
|
@@ -65,6 +67,15 @@ module Ruson
|
|
65
67
|
include Ruson::Querying
|
66
68
|
include Ruson::Value
|
67
69
|
|
70
|
+
# ~~~~ Class Methods ~~~~
|
71
|
+
def self.ensure_output_folder_is_defined
|
72
|
+
return if Ruson.output_folder
|
73
|
+
|
74
|
+
raise ArgumentError, 'No output folder defined. You can define it ' \
|
75
|
+
'using Ruson.output_folder = "/path/to/db/folder"'
|
76
|
+
end
|
77
|
+
|
78
|
+
# ~~~~ Instance Methods ~~~~
|
68
79
|
def initialize(json, root_key: nil)
|
69
80
|
params = get_hash_from_json(json)
|
70
81
|
params = params[root_key.to_s] unless root_key.nil?
|
@@ -77,8 +88,9 @@ module Ruson
|
|
77
88
|
|
78
89
|
res.inject({}) do |result, attributes|
|
79
90
|
key, value = attributes
|
80
|
-
|
81
|
-
|
91
|
+
accessor = self.class.accessors[key]
|
92
|
+
if accessor && accessor.key?(:name)
|
93
|
+
result[accessor[:name]] = value
|
82
94
|
else
|
83
95
|
result[key] = value
|
84
96
|
end
|
@@ -86,30 +98,38 @@ module Ruson
|
|
86
98
|
end
|
87
99
|
end
|
88
100
|
|
89
|
-
def to_json
|
90
|
-
to_hash
|
101
|
+
def to_json(options = {})
|
102
|
+
hash = to_hash
|
103
|
+
|
104
|
+
options[:exclude].each { |key| hash.delete(key) } if options[:exclude]
|
105
|
+
|
106
|
+
hash.to_json
|
91
107
|
end
|
92
108
|
|
93
109
|
private
|
94
110
|
|
111
|
+
def cast_value(value, accessor_options, options = {})
|
112
|
+
check_nilable(value, accessor_options)
|
113
|
+
get_val(value, accessor_options)
|
114
|
+
end
|
115
|
+
|
95
116
|
def init_attributes(accessors, params)
|
96
117
|
update_attributes(accessors, params)
|
97
118
|
|
98
119
|
self.class.attr_accessor(:id)
|
99
|
-
set_attribute(:id, params[:id]) if params[:id]
|
120
|
+
set_attribute(:id, params[:id]) if params && params[:id]
|
100
121
|
end
|
101
122
|
|
102
|
-
def set_attribute(attr_name,
|
103
|
-
|
123
|
+
def set_attribute(attr_name, value)
|
124
|
+
send("#{attr_name}=".to_sym, value)
|
104
125
|
end
|
105
126
|
|
106
127
|
def update_attributes(accessors, params)
|
107
128
|
accessors.each do |key, options|
|
108
|
-
value = params[options[:name]] || params[key]
|
129
|
+
value = params[options[:name]] || params[key] if params
|
109
130
|
|
110
|
-
|
111
|
-
|
112
|
-
set_attribute(key, val)
|
131
|
+
casted_value = cast_value(value, options)
|
132
|
+
set_attribute(key, casted_value)
|
113
133
|
end
|
114
134
|
end
|
115
135
|
end
|
data/lib/ruson/class/boolean.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
module Ruson
|
2
|
+
class Boolean
|
3
|
+
def self.new(value)
|
4
|
+
return value if value.kind_of?(TrueClass) || value.kind_of?(FalseClass)
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
case value
|
7
|
+
when 'true'
|
8
|
+
return true
|
9
|
+
when 'false'
|
10
|
+
return false
|
11
|
+
else
|
12
|
+
return false
|
13
|
+
end
|
12
14
|
end
|
13
15
|
end
|
14
|
-
end
|
16
|
+
end
|
data/lib/ruson/class/float.rb
CHANGED
data/lib/ruson/class/integer.rb
CHANGED
data/lib/ruson/class/time.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
1
|
+
module Ruson
|
2
|
+
class Time
|
3
|
+
def self.new(value)
|
4
|
+
case value
|
5
|
+
when ::Integer, ::Float
|
6
|
+
::Time.at(value).to_time
|
7
|
+
when ::String
|
8
|
+
::Time.parse(value).to_time
|
9
|
+
else
|
10
|
+
value
|
11
|
+
end
|
10
12
|
end
|
11
13
|
end
|
12
|
-
end
|
14
|
+
end
|
data/lib/ruson/converter.rb
CHANGED
data/lib/ruson/json.rb
CHANGED
@@ -1,8 +1,17 @@
|
|
1
1
|
module Ruson
|
2
2
|
module Json
|
3
3
|
def get_hash_from_json(json)
|
4
|
+
return unless json
|
4
5
|
return json if json.class == ActiveSupport::HashWithIndifferentAccess
|
6
|
+
|
5
7
|
(json.class == Hash ? json : JSON.parse(json)).with_indifferent_access
|
6
8
|
end
|
9
|
+
|
10
|
+
#
|
11
|
+
# Returns the ID from the JSON file path.
|
12
|
+
#
|
13
|
+
def id_from_file_path(path)
|
14
|
+
File.basename(path, '.json').to_i
|
15
|
+
end
|
7
16
|
end
|
8
17
|
end
|
data/lib/ruson/persistence.rb
CHANGED
@@ -2,6 +2,7 @@ module Ruson
|
|
2
2
|
module Persistence
|
3
3
|
def self.included(klass)
|
4
4
|
klass.extend(ClassMethods)
|
5
|
+
klass.extend(Ruson::Json)
|
5
6
|
end
|
6
7
|
|
7
8
|
module ClassMethods
|
@@ -25,13 +26,6 @@ module Ruson
|
|
25
26
|
true
|
26
27
|
end
|
27
28
|
|
28
|
-
def ensure_output_folder_is_defined
|
29
|
-
return if Ruson.output_folder
|
30
|
-
|
31
|
-
raise ArgumentError, 'No output folder defined. You can define it ' \
|
32
|
-
'using Ruson.output_folder = "/path/to/db/folder"'
|
33
|
-
end
|
34
|
-
|
35
29
|
def ensure_model_folder_exists
|
36
30
|
return if File.exist?(self.class.model_base_path)
|
37
31
|
|
@@ -45,8 +39,8 @@ module Ruson
|
|
45
39
|
|
46
40
|
id = 0
|
47
41
|
|
48
|
-
Dir.glob(File.join(self.class.model_base_path, '*.json')).each do |
|
49
|
-
file_id =
|
42
|
+
Dir.glob(File.join(self.class.model_base_path, '*.json')).each do |path|
|
43
|
+
file_id = id_from_file_path(path)
|
50
44
|
|
51
45
|
id = file_id if file_id > id
|
52
46
|
end
|
@@ -60,12 +54,12 @@ module Ruson
|
|
60
54
|
|
61
55
|
def write_file_to_disk
|
62
56
|
File.open(model_path, 'w') do |file|
|
63
|
-
file.write(to_json)
|
57
|
+
file.write(to_json(exclude: %i[id]))
|
64
58
|
end
|
65
59
|
end
|
66
60
|
|
67
61
|
def save
|
68
|
-
ensure_output_folder_is_defined
|
62
|
+
self.class.ensure_output_folder_is_defined
|
69
63
|
generate_uniq_id
|
70
64
|
write_file_to_disk
|
71
65
|
true
|
data/lib/ruson/querying.rb
CHANGED
@@ -2,18 +2,28 @@ module Ruson
|
|
2
2
|
module Querying
|
3
3
|
def self.included(klass)
|
4
4
|
klass.extend(ClassMethods)
|
5
|
+
klass.extend(Ruson::Json)
|
5
6
|
end
|
6
7
|
|
7
8
|
module ClassMethods
|
9
|
+
def all
|
10
|
+
ensure_output_folder_is_defined
|
11
|
+
|
12
|
+
model_files.collect do |path|
|
13
|
+
json = JSON.parse(File.read(path))
|
14
|
+
|
15
|
+
new(json.merge(id: id_from_file_path(path)))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
8
19
|
def find(id)
|
20
|
+
ensure_output_folder_is_defined
|
21
|
+
|
9
22
|
file_path = File.join(model_base_path, "#{id}.json")
|
10
23
|
|
11
24
|
return unless File.exist?(file_path)
|
12
25
|
|
13
|
-
|
14
|
-
json[:id] = id
|
15
|
-
|
16
|
-
new json
|
26
|
+
load(file_path, id: id)
|
17
27
|
end
|
18
28
|
|
19
29
|
def find!(id)
|
@@ -23,6 +33,58 @@ module Ruson
|
|
23
33
|
|
24
34
|
record
|
25
35
|
end
|
36
|
+
|
37
|
+
def first
|
38
|
+
ensure_output_folder_is_defined
|
39
|
+
|
40
|
+
file_path = model_files.first
|
41
|
+
|
42
|
+
return unless file_path
|
43
|
+
|
44
|
+
id = id_from_file_path(file_path)
|
45
|
+
|
46
|
+
load(file_path, id: id)
|
47
|
+
end
|
48
|
+
|
49
|
+
def first!
|
50
|
+
record = first
|
51
|
+
|
52
|
+
raise Ruson::RecordNotFound unless record
|
53
|
+
|
54
|
+
record
|
55
|
+
end
|
56
|
+
|
57
|
+
def load(file_path, extra_json = {})
|
58
|
+
json = JSON.parse(File.read(file_path))
|
59
|
+
|
60
|
+
json.merge!(extra_json) if extra_json
|
61
|
+
|
62
|
+
new json
|
63
|
+
end
|
64
|
+
|
65
|
+
def where(attributes)
|
66
|
+
ensure_output_folder_is_defined
|
67
|
+
|
68
|
+
query_attributes = attributes.stringify_keys
|
69
|
+
|
70
|
+
models = model_files.collect do |path|
|
71
|
+
json = JSON.parse(File.read(path))
|
72
|
+
|
73
|
+
query_attributes_matches = query_attributes.keys.all? do |key|
|
74
|
+
json[key] == query_attributes[key]
|
75
|
+
end
|
76
|
+
|
77
|
+
if query_attributes_matches
|
78
|
+
new(json.merge(id: id_from_file_path(path)))
|
79
|
+
end
|
80
|
+
end.compact
|
81
|
+
|
82
|
+
Array(models)
|
83
|
+
end
|
84
|
+
|
85
|
+
def model_files
|
86
|
+
Dir.glob(File.join(model_base_path, '*.json'))
|
87
|
+
end
|
26
88
|
end
|
27
89
|
end
|
28
90
|
end
|
data/lib/ruson/value.rb
CHANGED
data/lib/ruson/version.rb
CHANGED
data/ruson.gemspec
CHANGED
@@ -7,12 +7,13 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = 'ruson'
|
8
8
|
spec.version = Ruson::VERSION
|
9
9
|
spec.authors = ['klriutsa']
|
10
|
-
spec.email = ['hiroya
|
10
|
+
spec.email = ['kurushima.hiroya@gmail.com']
|
11
11
|
|
12
|
-
spec.summary = %q{
|
13
|
-
spec.description = %q{
|
12
|
+
spec.summary = %q{A Ruby serialization/deserialization library to convert Ruby Objects into JSON and back}
|
13
|
+
spec.description = %q{A Ruby serialization/deserialization library to convert Ruby Objects into JSON and back}
|
14
14
|
spec.homepage = 'https://github.com/klriutsa/ruson'
|
15
15
|
spec.license = 'MIT'
|
16
|
+
spec.required_ruby_version = '>= 2.5'
|
16
17
|
|
17
18
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
19
|
f.match(%r{^(test|spec|features)/})
|
@@ -25,7 +26,7 @@ Gem::Specification.new do |spec|
|
|
25
26
|
|
26
27
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
27
28
|
spec.add_development_dependency 'ffaker', '~> 2.13.0'
|
28
|
-
spec.add_development_dependency 'rake', '
|
29
|
+
spec.add_development_dependency 'rake', '>= 12.3.3'
|
29
30
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
30
31
|
spec.add_development_dependency 'timecop', '~> 0.9.1'
|
31
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruson
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- klriutsa
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -56,16 +56,16 @@ dependencies:
|
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 12.3.3
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 12.3.3
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,15 +94,17 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 0.9.1
|
97
|
-
description:
|
97
|
+
description: A Ruby serialization/deserialization library to convert Ruby Objects
|
98
|
+
into JSON and back
|
98
99
|
email:
|
99
|
-
- hiroya
|
100
|
+
- kurushima.hiroya@gmail.com
|
100
101
|
executables: []
|
101
102
|
extensions: []
|
102
103
|
extra_rdoc_files: []
|
103
104
|
files:
|
104
105
|
- ".gitignore"
|
105
106
|
- ".rspec"
|
107
|
+
- ".ruby-version"
|
106
108
|
- ".travis.yml"
|
107
109
|
- CODE_OF_CONDUCT.md
|
108
110
|
- Dockerfile
|
@@ -114,6 +116,7 @@ files:
|
|
114
116
|
- bin/setup
|
115
117
|
- lib/ruson.rb
|
116
118
|
- lib/ruson/base.rb
|
119
|
+
- lib/ruson/class/array.rb
|
117
120
|
- lib/ruson/class/boolean.rb
|
118
121
|
- lib/ruson/class/float.rb
|
119
122
|
- lib/ruson/class/integer.rb
|
@@ -139,15 +142,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
139
142
|
requirements:
|
140
143
|
- - ">="
|
141
144
|
- !ruby/object:Gem::Version
|
142
|
-
version: '
|
145
|
+
version: '2.5'
|
143
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
147
|
requirements:
|
145
148
|
- - ">="
|
146
149
|
- !ruby/object:Gem::Version
|
147
150
|
version: '0'
|
148
151
|
requirements: []
|
149
|
-
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 2.7.3
|
150
154
|
signing_key:
|
151
155
|
specification_version: 4
|
152
|
-
summary:
|
156
|
+
summary: A Ruby serialization/deserialization library to convert Ruby Objects into
|
157
|
+
JSON and back
|
153
158
|
test_files: []
|