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 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: []