ruson 1.2.0 → 1.3.4

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: df8812fa2f70ad440c16a4647961a68955b3909d481db38bd6271534afce154c
4
- data.tar.gz: d8877e9e6f435d319a736e0157845dae2264ba6468a2ed918b158601de2a8881
3
+ metadata.gz: fba9838b250ac9e2b66d41f371c2bf5c5bcd6614699cbae56fa16e453bd18ced
4
+ data.tar.gz: 79fb3b97b0e7f034ded6b547ee46f158b71adde353cbdb6e38af74d32903de56
5
5
  SHA512:
6
- metadata.gz: 5883b0fc7b4e95a713a906f83c1d3f07a2761cd1cf4a246f2ae6ee2591322fd24791c8ce99f37dc6e62338c4da55494d160428206838de34154e5402efcad409
7
- data.tar.gz: 20fb24a41b36de01dcb8bfcb32a864ed88808f49229617a610ceb5ced0ee8a0ca3bf4204c5100120349fee63f76a79948cd09f7d4b16afcb02e34dc8a0afd44e
6
+ metadata.gz: a112f20c0b9b09e1c83fc1e0b5450b7fe99022686e670a6932b15d17bb4a50defa7c64df0ec3fb714261f2108a8b0cc7c6ae67d911c110419006b9bdbb8fc295
7
+ data.tar.gz: a8337d211ff0a51fa57aab817bf1adc1becface00dd628f511fd14960399a4d9ece199a0a8302e001d529a62122a26733c81d728f591889151f36f6e0185d71f
data/.gitignore CHANGED
@@ -10,3 +10,6 @@
10
10
 
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
+
14
+ # IntelliJ IDEA
15
+ /.idea/
@@ -0,0 +1 @@
1
+ 2.5.0
@@ -0,0 +1,30 @@
1
+ # How to use it
2
+ # =============
3
+ #
4
+ # Visit https://blog.zedroot.org/2015/04/30/using-docker-to-maintain-a-ruby-gem/
5
+
6
+ # ~~~~ Image base ~~~~
7
+ # Base image
8
+ FROM ruby:2.6.5-alpine
9
+ LABEL maintainer="klriutsa"
10
+
11
+ RUN mkdir -p /gem/
12
+ WORKDIR /gem/
13
+ ADD . /gem/
14
+
15
+ # ~~~~ OS Maintenance & Rails Preparation ~~~~
16
+ # Rubygems and Bundler
17
+ RUN apk add --no-cache \
18
+ --quiet \
19
+ build-base \
20
+ git \
21
+ && touch ~/.gemrc \
22
+ && echo "gem: --no-ri --no-rdoc" >> ~/.gemrc \
23
+ && gem install rubygems-update \
24
+ && update_rubygems \
25
+ && gem install bundler \
26
+ && bundle install \
27
+ && rm -rf /var/cache/apk/*
28
+
29
+ ENTRYPOINT ["bundle", "exec"]
30
+ CMD ["rake", "-T"]
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
 
@@ -20,6 +20,8 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
+ ### Basic
24
+
23
25
  post.json
24
26
  ```json
25
27
  {
@@ -42,7 +44,7 @@ post.title #=> 'Ruson'
42
44
  post.content #=> 'Welcome!'
43
45
  ```
44
46
 
45
- ### name
47
+ #### name
46
48
 
47
49
  post.json
48
50
  ```json
@@ -65,7 +67,7 @@ post = Post.new(json)
65
67
  post.url #=> 'http://sample.com'
66
68
  ```
67
69
 
68
- ### nilable
70
+ #### nilable
69
71
 
70
72
  post.json
71
73
  ```json
@@ -85,9 +87,9 @@ json = File.read('post.json')
85
87
  post = Post.new(json) #=> Ruson::NotNilException
86
88
  ```
87
89
 
88
- ### nested class
90
+ #### nested class
89
91
 
90
- #### class
92
+ ##### class
91
93
 
92
94
  post.json
93
95
  ```json
@@ -119,39 +121,47 @@ post = Post.new(json)
119
121
  post.picture.url #=> 'http://sample.com/picture.png'
120
122
  ```
121
123
 
122
- ##### Primary classes
124
+ ###### Primary classes
123
125
 
124
- * Boolean
125
- * Integer
126
- * Float
126
+ * Ruson::Array
127
+ * Ruson::Boolean
128
+ * Ruson::Float
129
+ * Ruson::Integer
130
+ * Ruson::Time
127
131
 
128
132
 
129
133
  post.json
130
134
  ```json
131
135
  {
132
136
  "title": "Ruson",
137
+ "items": ["orange", "apple"],
133
138
  "is_new": "true",
139
+ "rate": "3.8",
134
140
  "view": "1234",
135
- "rate": "3.8"
141
+ "expired_at": 1575608299
136
142
  }
137
143
  ```
138
144
 
139
145
  ```ruby
140
146
  class Post < Ruson::Base
141
147
  field :title
142
- field :is_new, class: Boolean
143
- field :view, class: Integer
144
- 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
145
153
  end
146
154
 
147
155
  json = File.read('post.json')
148
156
  post = Post.new(json)
157
+ post.items #=> ["orange", "apple"]
149
158
  post.is_new #=> true
150
- post.view #=> 1234
151
159
  post.rate #=> 3.8
160
+ post.view #=> 1234
161
+ post.expired_at #=> 2019-12-06 04:58:19 +0000
152
162
  ```
153
163
 
154
- #### each class
164
+ ##### each class
155
165
 
156
166
  post.json
157
167
  ```json
@@ -185,7 +195,7 @@ post = Post.new(json)
185
195
  post.tags.first.name #=> 'Ruby'
186
196
  ```
187
197
 
188
- ### enum
198
+ #### enum
189
199
 
190
200
  article.json
191
201
  ```json
@@ -213,7 +223,7 @@ article.status = 'undefined'
213
223
  #=> undefined is not a valid status (ArgumentError)
214
224
  ```
215
225
 
216
- ### to_json
226
+ #### to_json
217
227
 
218
228
  ```ruby
219
229
  class Post < Ruson::Base
@@ -228,7 +238,7 @@ post.url = 'https://example.com/examples'
228
238
  post.to_json #=> "{\"title\":\"Ruson\",\"url\":\"https://example.com/examples\"}"
229
239
  ```
230
240
 
231
- ### to_hash
241
+ #### to_hash
232
242
 
233
243
  ```ruby
234
244
  class Post < Ruson::Base
@@ -243,7 +253,7 @@ post.url = 'https://example.com/examples'
243
253
  post.to_hash #=> {title: "Ruson", url: "https://example.com/examples" }
244
254
  ```
245
255
 
246
- ### API json parser
256
+ #### API json parser
247
257
 
248
258
  ```ruby
249
259
  class Article < Ruson::Base
@@ -261,12 +271,170 @@ article = Article.new(response.body)
261
271
  article.title
262
272
  ```
263
273
 
274
+ ### Persistence
275
+
276
+ Persistence will save the models as JSON file, with the model ID as filename, and model class name as parent folder so that a `User` model with ID `1` will be saved as `Users/1.json`.
277
+
278
+ You *must* define the `output_folder` before to be able to call `save` or `destroy`.
279
+
280
+ ```ruby
281
+ Ruson.output_folder = './db/'
282
+ ```
283
+
284
+ #### Creating new record
285
+
286
+ ```ruby
287
+ class User < Ruson::Base
288
+ field :first_name
289
+ field :last_name
290
+ field :email
291
+ field :title
292
+ end
293
+
294
+ # Using new + save
295
+ guillaume = User.new(first_name: 'Guillaume', last_name: 'Briat', email: 'guillaume@kaamelott.fr')
296
+ guillaume.save # Creates the ./db/Users/1.json file
297
+
298
+ # Or using the create method
299
+ guillaume = User.create(first_name: 'Guillaume', last_name: 'Briat', email: 'guillaume@kaamelott.fr')
300
+
301
+ puts File.read('./db/Users/1.json')
302
+ {"first_name":"Guillaume","last_name":"Briat","email":"guillaume@kaamelott.fr"}
303
+ => nil
304
+ ```
305
+
306
+ #### Updating a record
307
+
308
+ ```ruby
309
+ # Assigning a value + save
310
+ guillaume.title = 'Burgundians King'
311
+ guillaume.save # Updates the ./db/Users/1.json file
312
+
313
+ # Or using the update method
314
+ guillaume.update(title: 'Burgundians King')
315
+
316
+ puts File.read('./db/Users/1.json')
317
+ {"first_name":"Guillaume","last_name":"Briat","email":"guillaume@kaamelott.fr","title":"Burgundians King"}
318
+ => nil
319
+ ```
320
+
321
+ #### Destroying a record
322
+
323
+ ```ruby
324
+ guillaume.destroy # Deletes the ./db/Users/1.json file
325
+
326
+ puts File.read('./db/Users/1.json')
327
+ Traceback (most recent call last):
328
+ 16: from /usr/local/bundle/gems/bundler-2.0.2/exe/bundle:30:in `block in <top (required)>'
329
+ ...
330
+ 2: from (irb):26
331
+ 1: from (irb):26:in `read'
332
+ Errno::ENOENT (No such file or directory @ rb_sysopen - ./db/Users/1.json)
333
+ ```
334
+
335
+ ### Querying
336
+
337
+ Ruson allows you to query for existing records.
338
+
339
+ You *must* define the `output_folder` before to query records.
340
+
341
+ ```ruby
342
+ Ruson.output_folder = './db/'
343
+ ```
344
+
345
+ #### Find a record by ID
346
+
347
+ ```ruby
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>]
392
+ ```
393
+
264
394
  ## Development
265
395
 
396
+ ### Without Docker
397
+
266
398
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
267
399
 
268
400
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
269
401
 
402
+ ### With Docker
403
+
404
+ ```
405
+ $ docker build -t `whoami`/ruson .
406
+ ```
407
+
408
+ In order to see the available Rake tasks:
409
+
410
+ ```
411
+ $ docker --rm `whoami`/ruson
412
+ rake build # Build ruson-1.2.0.gem into the pkg directory
413
+ rake clean # Remove any temporary products
414
+ rake clobber # Remove any generated files
415
+ rake install # Build and install ruson-1.2.0.gem into system gems
416
+ rake install:local # Build and install ruson-1.2.0.gem into system gems without network access
417
+ rake release[remote] # Create tag v1.2.0 and build and push ruson-1.2.0.gem to rubygems.org
418
+ rake spec # Run RSpec code examples
419
+ ```
420
+ _`--rm` means delete the container after the command has ended._
421
+
422
+ In order to execute the tests:
423
+
424
+ ```
425
+ $ docker run --rm -it --volume "$PWD":/gem/ `whoami`/ruson rake spec
426
+ ```
427
+ _`--volume` is used to sync the files from your current folder into the container so that if you change a file, the modification is available in the container._
428
+
429
+ In the case you'd like to access the IRB console:
430
+
431
+ ```
432
+ $ docker run --rm -it --volume "$PWD":/gem/ `whoami`/ruson irb
433
+ irb(main):001:0> require 'ruson'
434
+ => true
435
+ irb(main):002:0>
436
+ ```
437
+
270
438
  ## Contributing
271
439
 
272
440
  Bug reports and pull requests are welcome on GitHub at https://github.com/klriutsa/ruson. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
@@ -2,5 +2,6 @@ require 'ruson/base'
2
2
  require 'ruson/version'
3
3
 
4
4
  module Ruson
5
-
5
+ # Output folder where Ruson will save models data
6
+ mattr_accessor :output_folder
6
7
  end
@@ -2,14 +2,18 @@ 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
- require 'ruson/class/integer'
7
7
  require 'ruson/class/float'
8
+ require 'ruson/class/integer'
9
+ require 'ruson/class/time'
8
10
 
9
11
  require 'ruson/converter'
10
12
  require 'ruson/json'
11
- require 'ruson/value'
12
13
  require 'ruson/nilable'
14
+ require 'ruson/persistence'
15
+ require 'ruson/querying'
16
+ require 'ruson/value'
13
17
 
14
18
  require 'ruson/error'
15
19
 
@@ -48,16 +52,30 @@ module Ruson
48
52
  end
49
53
 
50
54
  def add_accessor(name, options = {})
55
+ options[:name] = options[:name].try(:to_sym) if options[:name]
56
+
51
57
  @accessors ||= {}
52
58
  @accessors.merge!({ name.to_sym => options })
53
59
  end
54
60
  end
55
61
 
62
+ # ~~~~ Mixins ~~~~
56
63
  include Ruson::Converter
57
64
  include Ruson::Json
58
- include Ruson::Value
59
65
  include Ruson::Nilable
66
+ include Ruson::Persistence
67
+ include Ruson::Querying
68
+ include Ruson::Value
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
60
77
 
78
+ # ~~~~ Instance Methods ~~~~
61
79
  def initialize(json, root_key: nil)
62
80
  params = get_hash_from_json(json)
63
81
  params = params[root_key.to_s] unless root_key.nil?
@@ -66,28 +84,53 @@ module Ruson
66
84
  end
67
85
 
68
86
  def to_hash
69
- convert_to_hash(self.class.accessors)
87
+ res = convert_to_hash(self.class.accessors)
88
+
89
+ res.inject({}) do |result, attributes|
90
+ key, value = attributes
91
+ accessor = self.class.accessors[key]
92
+ if accessor && accessor.key?(:name)
93
+ result[accessor[:name]] = value
94
+ else
95
+ result[key] = value
96
+ end
97
+ result
98
+ end
70
99
  end
71
100
 
72
- def to_json
73
- 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
74
107
  end
75
108
 
76
109
  private
77
110
 
111
+ def cast_value(value, accessor_options, options = {})
112
+ check_nilable(value, accessor_options)
113
+ get_val(value, accessor_options)
114
+ end
115
+
78
116
  def init_attributes(accessors, params)
79
- accessors.each do |key, options|
80
- key_name = options[:name] || key
81
- value = params[key_name]
117
+ update_attributes(accessors, params)
82
118
 
83
- check_nilable(value, options)
84
- val = get_val(value, options)
85
- set_attribute(key, val)
86
- end
119
+ self.class.attr_accessor(:id)
120
+ set_attribute(:id, params[:id]) if params && params[:id]
87
121
  end
88
122
 
89
- def set_attribute(attr_name, val)
90
- self.send("#{attr_name}=".to_sym, val)
123
+ def set_attribute(attr_name, value)
124
+ send("#{attr_name}=".to_sym, value)
125
+ end
126
+
127
+ def update_attributes(accessors, params)
128
+ accessors.each do |key, options|
129
+ value = params[options[:name]] || params[key] if params
130
+
131
+ casted_value = cast_value(value, options)
132
+ set_attribute(key, casted_value)
133
+ end
91
134
  end
92
135
  end
93
136
  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
@@ -0,0 +1,14 @@
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
12
+ end
13
+ end
14
+ end
@@ -1,7 +1,7 @@
1
1
  module Ruson
2
2
  module Converter
3
3
  def convert_to_hash(accessors)
4
- accessors.keys.inject({}) do |result, key|
4
+ accessors.keys.inject({ id: id }) do |result, key|
5
5
  value = send(key)
6
6
  result[key.to_sym] = convert_array_to_hash_value(value)
7
7
  result
@@ -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)
@@ -1,4 +1,4 @@
1
1
  module Ruson
2
- class NotNilException < StandardError
3
- end
4
- end
2
+ class NotNilException < StandardError; end
3
+ class RecordNotFound < StandardError; end
4
+ end
@@ -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
@@ -0,0 +1,83 @@
1
+ module Ruson
2
+ module Persistence
3
+ def self.included(klass)
4
+ klass.extend(ClassMethods)
5
+ klass.extend(Ruson::Json)
6
+ end
7
+
8
+ module ClassMethods
9
+ def create(*args)
10
+ new_record = new(*args)
11
+ new_record.save
12
+ new_record
13
+ end
14
+
15
+ def model_base_path
16
+ File.join(Ruson.output_folder, "#{self.name}s")
17
+ end
18
+ end
19
+
20
+ def delete_file_from_disk
21
+ FileUtils.rm_f(model_path)
22
+ end
23
+
24
+ def destroy
25
+ delete_file_from_disk
26
+ true
27
+ end
28
+
29
+ def ensure_model_folder_exists
30
+ return if File.exist?(self.class.model_base_path)
31
+
32
+ FileUtils.mkdir_p(self.class.model_base_path)
33
+ end
34
+
35
+ def generate_uniq_id
36
+ ensure_model_folder_exists
37
+
38
+ return if id
39
+
40
+ id = 0
41
+
42
+ Dir.glob(File.join(self.class.model_base_path, '*.json')).each do |path|
43
+ file_id = id_from_file_path(path)
44
+
45
+ id = file_id if file_id > id
46
+ end
47
+
48
+ self.id = id + 1
49
+ end
50
+
51
+ def model_path
52
+ File.join(self.class.model_base_path, "#{id}.json")
53
+ end
54
+
55
+ def write_file_to_disk
56
+ File.open(model_path, 'w') do |file|
57
+ file.write(to_json(exclude: %i[id]))
58
+ end
59
+ end
60
+
61
+ def save
62
+ self.class.ensure_output_folder_is_defined
63
+ generate_uniq_id
64
+ write_file_to_disk
65
+ true
66
+ end
67
+
68
+ def update(attributes)
69
+ attributes.symbolize_keys!
70
+
71
+ # Takes only accessor for attributes to be updated, avoiding to nullify
72
+ # the other attributes.
73
+ filtered_accessors = self.class.accessors.select do |key, accessor_attrs|
74
+ attributes.key?(key) || attributes.key?(accessor_attrs[:name])
75
+ end
76
+
77
+ update_attributes(filtered_accessors, attributes)
78
+
79
+ save
80
+ end
81
+ end
82
+ end
83
+
@@ -0,0 +1,90 @@
1
+ module Ruson
2
+ module Querying
3
+ def self.included(klass)
4
+ klass.extend(ClassMethods)
5
+ klass.extend(Ruson::Json)
6
+ end
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
+
19
+ def find(id)
20
+ ensure_output_folder_is_defined
21
+
22
+ file_path = File.join(model_base_path, "#{id}.json")
23
+
24
+ return unless File.exist?(file_path)
25
+
26
+ load(file_path, id: id)
27
+ end
28
+
29
+ def find!(id)
30
+ record = find(id)
31
+
32
+ raise Ruson::RecordNotFound unless record
33
+
34
+ record
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
88
+ end
89
+ end
90
+ end
@@ -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
 
@@ -1,3 +1,3 @@
1
1
  module Ruson
2
- VERSION = '1.2.0'
2
+ VERSION = '1.3.4'
3
3
  end
@@ -1,28 +1,32 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
2
+ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "ruson/version"
4
+ require 'ruson/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "ruson"
7
+ spec.name = 'ruson'
8
8
  spec.version = Ruson::VERSION
9
- spec.authors = ["klriutsa"]
10
- spec.email = ["hiroya.kurushima@litalico.co.jp"]
9
+ spec.authors = ['klriutsa']
10
+ spec.email = ['kurushima.hiroya@gmail.com']
11
11
 
12
- spec.summary = %q{ruby json library.}
13
- spec.description = %q{ruby json library.}
14
- spec.homepage = "https://github.com/klriutsa/ruson"
15
- spec.license = "MIT"
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
+ spec.homepage = 'https://github.com/klriutsa/ruson'
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)/})
19
20
  end
20
- spec.bindir = "exe"
21
+ spec.bindir = 'exe'
21
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
- spec.require_paths = ["lib"]
23
+ spec.require_paths = ['lib']
23
24
 
24
- spec.add_development_dependency "bundler", "~> 2.0"
25
- spec.add_development_dependency "rake", "~> 10.0"
26
- spec.add_development_dependency "rspec", "~> 3.0"
27
25
  spec.add_dependency 'activesupport'
26
+
27
+ spec.add_development_dependency 'bundler', '~> 2.0'
28
+ spec.add_development_dependency 'ffaker', '~> 2.13.0'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'rspec', '~> 3.0'
31
+ spec.add_development_dependency 'timecop', '~> 0.9.1'
28
32
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruson
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - klriutsa
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-09-27 00:00:00.000000000 Z
11
+ date: 2020-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +38,20 @@ dependencies:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
40
  version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ffaker
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 2.13.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 2.13.0
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: rake
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -53,30 +81,33 @@ dependencies:
53
81
  - !ruby/object:Gem::Version
54
82
  version: '3.0'
55
83
  - !ruby/object:Gem::Dependency
56
- name: activesupport
84
+ name: timecop
57
85
  requirement: !ruby/object:Gem::Requirement
58
86
  requirements:
59
- - - ">="
87
+ - - "~>"
60
88
  - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :runtime
89
+ version: 0.9.1
90
+ type: :development
63
91
  prerelease: false
64
92
  version_requirements: !ruby/object:Gem::Requirement
65
93
  requirements:
66
- - - ">="
94
+ - - "~>"
67
95
  - !ruby/object:Gem::Version
68
- version: '0'
69
- description: ruby json library.
96
+ version: 0.9.1
97
+ description: A Ruby serialization/deserialization library to convert Ruby Objects
98
+ into JSON and back
70
99
  email:
71
- - hiroya.kurushima@litalico.co.jp
100
+ - kurushima.hiroya@gmail.com
72
101
  executables: []
73
102
  extensions: []
74
103
  extra_rdoc_files: []
75
104
  files:
76
105
  - ".gitignore"
77
106
  - ".rspec"
107
+ - ".ruby-version"
78
108
  - ".travis.yml"
79
109
  - CODE_OF_CONDUCT.md
110
+ - Dockerfile
80
111
  - Gemfile
81
112
  - LICENSE.txt
82
113
  - README.md
@@ -85,13 +116,17 @@ files:
85
116
  - bin/setup
86
117
  - lib/ruson.rb
87
118
  - lib/ruson/base.rb
119
+ - lib/ruson/class/array.rb
88
120
  - lib/ruson/class/boolean.rb
89
121
  - lib/ruson/class/float.rb
90
122
  - lib/ruson/class/integer.rb
123
+ - lib/ruson/class/time.rb
91
124
  - lib/ruson/converter.rb
92
125
  - lib/ruson/error.rb
93
126
  - lib/ruson/json.rb
94
127
  - lib/ruson/nilable.rb
128
+ - lib/ruson/persistence.rb
129
+ - lib/ruson/querying.rb
95
130
  - lib/ruson/value.rb
96
131
  - lib/ruson/version.rb
97
132
  - ruson.gemspec
@@ -107,15 +142,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
107
142
  requirements:
108
143
  - - ">="
109
144
  - !ruby/object:Gem::Version
110
- version: '0'
145
+ version: '2.5'
111
146
  required_rubygems_version: !ruby/object:Gem::Requirement
112
147
  requirements:
113
148
  - - ">="
114
149
  - !ruby/object:Gem::Version
115
150
  version: '0'
116
151
  requirements: []
117
- rubygems_version: 3.0.3
152
+ rubyforge_project:
153
+ rubygems_version: 2.7.3
118
154
  signing_key:
119
155
  specification_version: 4
120
- summary: ruby json library.
156
+ summary: A Ruby serialization/deserialization library to convert Ruby Objects into
157
+ JSON and back
121
158
  test_files: []