ruson 1.3.0 → 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3b5eacde447ed93d7ecffd81ba095d20dad1398687f5138dd7f2267bfd5bacf
4
- data.tar.gz: 172098d6792639c7c785eba55332b323785c879ce59458766d60787458b043bc
3
+ metadata.gz: ed994824268107e491819721d5566eb742d97fc062179ca8f31e5e63c5886c22
4
+ data.tar.gz: '09e7b5315cc8612dec090b87b2d452db1c1c95338f4a6693ece851a6ba407ccb'
5
5
  SHA512:
6
- metadata.gz: 1e33b1b04e784cc26494d08fb02a26c9afa9f42bd3595c6f4527da6f59ce937c8df8b4d4b8d95bf528d6ecdbc9384cddc80de738b59d5224098fd9c4c45da3da
7
- data.tar.gz: 5cb1a2daa61f905266afb804878a59a0f617e19d530649651c2fbd978c9854c87c243d1002c7baa4e11bc95b6590e75207f4a2af5942941444d378693cbec1f2
6
+ metadata.gz: 2c8f9b71aa0c7ac63f93bd67ebc3e7b063c16ef118e6e67e846df6d8f445f3b6e0ef5c6a8a9638d0e6b421231afe7a2bc4c9345a0fc036650a7e3da027f446c7
7
+ data.tar.gz: 2202ca458dd9f29eba01e242e4b302dc8e1730a80eeb563bf036f4f7be01be52570c1a03550b1597ed3d71daf1e25e8fdffbdd1659b035dd6f636c08e7cac63d
data/.gitignore CHANGED
@@ -10,3 +10,6 @@
10
10
 
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
+
14
+ # IntelliJ IDEA
15
+ /.idea/
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
- Json ORM for Ruby Object
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
- * Boolean
127
- * Integer
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
- "rate": "3.8"
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 :is_new, class: Boolean
145
- field :view, class: Integer
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
- user = User.find(1) # Searches for a ./db/Users/1.json file
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
- if self.class.accessors[key] && self.class.accessors[key].key?(:name)
81
- result[self.class.accessors[key][:name].to_s] = value
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.to_json
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, val)
103
- self.send("#{attr_name}=".to_sym, val)
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
- check_nilable(value, options)
111
- val = get_val(value, options)
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
@@ -0,0 +1,7 @@
1
+ module Ruson
2
+ class Array
3
+ def self.new(value)
4
+ Array(value)
5
+ end
6
+ end
7
+ end
@@ -1,14 +1,16 @@
1
- class Boolean
2
- def self.new(value)
3
- return value if value.kind_of?(TrueClass) || value.kind_of?(FalseClass)
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
- case value
6
- when 'true'
7
- return true
8
- when 'false'
9
- return false
10
- else
11
- return false
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
@@ -1,5 +1,7 @@
1
- class Float
2
- def self.new(value)
3
- value.to_f
1
+ module Ruson
2
+ class Float
3
+ def self.new(value)
4
+ value.to_f
5
+ end
4
6
  end
5
- end
7
+ end
@@ -1,5 +1,7 @@
1
- class Integer
2
- def self.new(value)
3
- value.to_i
1
+ module Ruson
2
+ class Integer
3
+ def self.new(value)
4
+ value.to_i
5
+ end
4
6
  end
5
- end
7
+ end
@@ -1,12 +1,14 @@
1
- class Time
2
- def self.new(value)
3
- case value
4
- when Integer, Float
5
- Time.at(value).to_time
6
- when String
7
- Time.parse(value).to_time
8
- else
9
- value
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
@@ -11,7 +11,7 @@ module Ruson
11
11
  private
12
12
 
13
13
  def convert_array_to_hash_value(value)
14
- if value.instance_of?(Array)
14
+ if value.instance_of?(::Array)
15
15
  value.inject([]) { |result, v| result << convert_ruson_to_hash_value(v) }
16
16
  else
17
17
  convert_ruson_to_hash_value(value)
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
@@ -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 |file|
49
- file_id = File.basename(file, '.json').to_i
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
@@ -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
- json = JSON.parse(File.read(file_path))
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
@@ -13,7 +13,6 @@ module Ruson
13
13
  private
14
14
 
15
15
  def class_param(param, klass)
16
- return nil if param.nil?
17
16
  klass.new(param)
18
17
  end
19
18
 
data/lib/ruson/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ruson
2
- VERSION = '1.3.0'
2
+ VERSION = '1.3.5'
3
3
  end
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.kurushima@litalico.co.jp']
10
+ spec.email = ['kurushima.hiroya@gmail.com']
11
11
 
12
- spec.summary = %q{ruby json library.}
13
- spec.description = %q{ruby json library.}
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', '~> 10.0'
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.0
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: 2019-12-03 00:00:00.000000000 Z
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: '10.0'
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: '10.0'
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: ruby json library.
97
+ description: A Ruby serialization/deserialization library to convert Ruby Objects
98
+ into JSON and back
98
99
  email:
99
- - hiroya.kurushima@litalico.co.jp
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: '0'
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
- rubygems_version: 3.0.6
152
+ rubyforge_project:
153
+ rubygems_version: 2.7.3
150
154
  signing_key:
151
155
  specification_version: 4
152
- summary: ruby json library.
156
+ summary: A Ruby serialization/deserialization library to convert Ruby Objects into
157
+ JSON and back
153
158
  test_files: []