ruson 1.2.0 → 1.3.4

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