class_from_son 0.1.6 → 0.2.2

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: abf5d4e89cc9bf59334246eb70e5f81ee9e8dab9b48e7585879ad3c81013d18c
4
- data.tar.gz: e1810cf3ee2f162217dce26e53de3c7b30d0e3b6a141a969b7404aad221e6f42
3
+ metadata.gz: 86fd5ffbcbad4d75f5ba1415762ef98380c2752c0fdd523e5b903cda8fedcf35
4
+ data.tar.gz: f89cad4aad4fee289a266b774080a06db9165145e5a26fb852be1f2f6a1f647d
5
5
  SHA512:
6
- metadata.gz: c758b0ebf50b308cc29bb7a122346e39e0b185b7144afec35942387a4a4323d8ca369635a5167f3ee3891955ee8ef3352443e2c247c39ec0a9346d7c75013a3b
7
- data.tar.gz: e148c2ff366ea22b46cbc3050604f7bf3cf9f58bbb1b79bea8b1ba82ea5949acc9d328aba65ec42e030092f0ee750708fe4f39106ee7d659cad5743922de0323
6
+ metadata.gz: 160a134313363eb41fb3ba88bd54272c6d8c127c61f6201266689df24a2db82c5a5919c14d0e9dde81946eaf9837523ad16b6a040f9b4a80177dc676f24df420
7
+ data.tar.gz: 52647cc8256cb44ec638a43850c4a009bf09fdcfda56440f00bd47262f1e4e499b8699fd8b195ce3e09c2a2fe5c5c65ebcc3cf91b19320216a920f0f35831293
data/README.md CHANGED
@@ -31,6 +31,12 @@ or
31
31
  ruby -e "require 'class_from_son'; ClassFromSON.generate :ruby, my_json_string, :json"
32
32
  ```
33
33
 
34
+ Advanced use :
35
+
36
+ ```
37
+ ruby -e "require 'class_from_son'; ClassFromSON.generate :ruby, my_json_string, :json, true, false, true, '../write/files/somewhere/else'"
38
+ ```
39
+
34
40
  Method parameter explanations :
35
41
 
36
42
  ```
@@ -42,7 +48,10 @@ Method parameter explanations :
42
48
  # source_lang is symbol or nil (if nil, source language will be determined from the file extension)
43
49
  # make_file flag defaults to true; set to false if you do not want files to be created by this method
44
50
  # force_file flag is false; set to true if you wish to overwrite matching destination files (use with caution!)
45
- def ClassFromSON.generate_from_file(dest_lang, file, source_lang, make_file = true, force_file = false)
51
+ # lenient_mode flag is true; if the SON contains different objects with the same name (e.g. "data") then these will be treated
52
+ # as different objects with a _1, _2, etc. suffix. If this flag is false and these different objects are present, then errors will occur
53
+ # custom_file_path is nil; set to an absoulte or relative path to have the new files be written to that location
54
+ def ClassFromSON.generate_from_file(dest_lang, file, source_lang = nil, make_file = true, force_file = false, lenient_mode = true, custom_file_path = nil)
46
55
  ```
47
56
 
48
57
  ```
@@ -54,5 +63,8 @@ def ClassFromSON.generate_from_file(dest_lang, file, source_lang, make_file = tr
54
63
  # source_lang is symbol
55
64
  # make_file flag defaults to true; set to false if you do not want files to be created by this method
56
65
  # force_file flag is false; set to true if you wish to overwrite matching destination files (use with caution!)
57
- def ClassFromSON.generate(dest_lang, source, source_lang, make_file = true, force_file = false)
66
+ # lenient_mode flag is true; if the SON contains different objects with the same name (e.g. "data") then these will be treated
67
+ # as different objects with a _1, _2, etc. suffix. If this flag is false and these different objects are present, then errors will occur
68
+ # custom_file_path is nil; set to an absoulte or relative path to have the new files be written to that location
69
+ def ClassFromSON.generate(dest_lang, source, source_lang, make_file = true, force_file = false, lenient_mode = true, custom_file_path = nil)
58
70
  ```
@@ -172,15 +172,16 @@ class ClassFromSON
172
172
 
173
173
  # Returns code representing the start of the class
174
174
  def generate_class_start(name)
175
+ # TODO make this more readable
175
176
  case @language
176
- when :java, :java_lombok
177
+ when :java
177
178
  start = <<-START
178
179
 
179
180
  import com.fasterxml.jackson.annotation.JsonProperty;
180
181
 
181
182
  public class #{convert_custom_class_type(name)} {
182
183
  START
183
- when :java_lombok # TODO
184
+ when :java_lombok
184
185
  start = <<-START
185
186
 
186
187
  import com.fasterxml.jackson.annotation.JsonProperty;
@@ -199,7 +200,16 @@ import lombok.Setter;
199
200
  public class #{convert_custom_class_type(name)} {
200
201
  START
201
202
  when :ruby
202
- start = "class #{convert_custom_class_type(name)}"
203
+ case @mode
204
+ when :json
205
+ start = <<-START
206
+ require 'json'
207
+
208
+ class #{convert_custom_class_type(name)}
209
+ START
210
+ else
211
+ error_and_exit "Cannot parse mode #{@mode}"
212
+ end
203
213
  else
204
214
  error_and_exit "Could not convert to output language #{@language}"
205
215
  end
@@ -285,21 +295,94 @@ START
285
295
  def generate_ruby_code_from_attributes(attributes)
286
296
  code = []
287
297
  names = []
288
- attributes.each {|att| names << att[:name]}
298
+ attributes.each {|att| names << att[:name].snakecase}
289
299
 
290
300
  # Instance variables
291
301
  names.each do |name|
292
- code << "\tattr_accessor #{name.to_sym.inspect}"
302
+ code << " attr_accessor #{name.to_sym.inspect}"
293
303
  end
294
304
  code << "" # An empty string is enough to trigger a newline
295
305
 
296
306
  # Constructor
297
- code << "\tdef initialize(#{names.join(", ")})"
307
+ # This is deliberately commented out, in favour of self.from_hash
308
+ code << " # Using self.from_hash(hash) is usually better, but this code is here in case you prefer this style of constructor"
309
+ code << " # def initialize(#{names.join(", ")})"
310
+ names.each do |name|
311
+ code << " # @#{name} = #{name}"
312
+ end
313
+ code << " # end"
314
+ code
315
+ end
316
+
317
+ # Returns code for a from_SON and to_SON method
318
+ def generate_from_and_to_methods(classname, attributes)
319
+ case @language
320
+ when :java, :java_lombok
321
+ return generate_java_from_and_to_methods(classname, attributes)
322
+ when :ruby
323
+ return generate_ruby_from_and_to_methods(classname, attributes)
324
+ else
325
+ error_and_exit "Could not convert to output language #{@language}"
326
+ end
327
+ end
328
+
329
+ # Returns Java code for a from_SON and to_SON method
330
+ def generate_java_from_and_to_methods(classname, attributes)
331
+ code = []
332
+ # TODO
333
+ code
334
+ end
335
+
336
+ # Returns Ruby code for a from_SON and to_SON method
337
+ def generate_ruby_from_and_to_methods(classname, attributes)
338
+ code = []
339
+ names = []
340
+ attributes.each {|att| names << att[:name].snakecase}
341
+
342
+ # from_hash method
343
+ code << ""
344
+ code << " def self.from_hash(h)"
345
+ code << " o = self.new"
346
+ names.each do |name|
347
+ code << " o.#{name} = h[:#{name}]"
348
+ end
349
+ code << " o"
350
+ code << " end"
351
+
352
+ # from_SON method
353
+ code << ""
354
+ code << " def self.from_#{@mode}(#{@mode})"
355
+ case @mode
356
+ when :json
357
+ code << " self.from_hash(JSON.parse(#{@mode}, :symbolize_names => true))"
358
+ # TODO other input languages, e.g. XML, YAML
359
+ end
360
+ code << " end"
361
+
362
+ # to_hash method
363
+ code << ""
364
+ code << " def to_hash"
365
+ code << " h = {}"
298
366
  names.each do |name|
299
- code << "\t\t@#{name} = #{name}"
367
+ code << " h[:#{name}] = @#{name}"
300
368
  end
301
- code << "\tend"
369
+ code << " h"
370
+ code << " end"
302
371
 
372
+ # to_SON method & alias
373
+ code << ""
374
+ code << " def to_#{@mode}"
375
+ case @mode
376
+ when :json
377
+ code << " JSON.generate(to_hash)"
378
+ # TODO other input languages, e.g. XML, YAML
379
+ end
380
+ code << " end"
381
+ case @mode
382
+ when :json
383
+ code << " alias to_s to_json"
384
+ # TODO other input languages, e.g. XML, YAML
385
+ end
303
386
  code
304
387
  end
305
388
 
@@ -337,6 +420,7 @@ START
337
420
  end
338
421
 
339
422
  lines << generate_code_from_attributes(attributes)
423
+ lines << generate_from_and_to_methods(classname, attributes)
340
424
  lines << generate_class_end
341
425
  lines.flatten!
342
426
  this_file[:contents] = lines.join("\n")
@@ -356,13 +440,16 @@ START
356
440
  # source_lang is symbol or nil (if nil, source language will be determined from the file extension)
357
441
  # make_file flag defaults to true; set to false if you do not want files to be created by this method
358
442
  # force_file flag is false; set to true if you wish to overwrite matching destination files (use with caution!)
359
- def ClassFromSON.generate_from_file(dest_lang, file, source_lang = nil, make_file = true, force_file = false)
443
+ # lenient_mode flag is true; if the SON contains different objects with the same name (e.g. "data") then these will be treated
444
+ # as different objects with a _1, _2, etc. suffix. If this flag is false and these different objects are present, then errors will occur
445
+ # custom_file_path is nil; set to an absoulte or relative path to have the new files be written to that location
446
+ def ClassFromSON.generate_from_file(dest_lang, file, source_lang = nil, make_file = true, force_file = false, lenient_mode = true, custom_file_path = nil)
360
447
 
361
448
  error_and_exit "Could not locate file #{file}" unless File.exists?(file)
362
449
 
363
450
  source_lang ||= File.extname(file).gsub(".", "")
364
451
  source = File.readlines(file).join
365
- ClassFromSON.generate(dest_lang, source, source_lang, make_file, force_file)
452
+ ClassFromSON.generate(dest_lang, source, source_lang, make_file, force_file, lenient_mode, custom_file_path)
366
453
 
367
454
  # o = ClassFromSON.new
368
455
  # o.generate(dest_lang, source, source_lang, make_file)
@@ -376,9 +463,12 @@ START
376
463
  # source_lang is symbol
377
464
  # make_file flag defaults to true; set to false if you do not want files to be created by this method
378
465
  # force_file flag is false; set to true if you wish to overwrite matching destination files (use with caution!)
379
- def ClassFromSON.generate(dest_lang, source, source_lang, make_file = true, force_file = false)
466
+ # lenient_mode flag is true; if the SON contains different objects with the same name (e.g. "data") then these will be treated
467
+ # as different objects with a _1, _2, etc. suffix. If this flag is false and these different objects are present, then errors will occur
468
+ # custom_file_path is nil; set to an absoulte or relative path to have the new files be written to that location
469
+ def ClassFromSON.generate(dest_lang, source, source_lang, make_file = true, force_file = false, lenient_mode = true, custom_file_path = nil)
380
470
  o = ClassFromSON.new
381
- o.generate(dest_lang, source, source_lang, make_file, force_file)
471
+ o.generate(dest_lang, source, source_lang, make_file, force_file, lenient_mode, custom_file_path)
382
472
  end
383
473
 
384
474
  # Will generate classes from a SON string.
@@ -389,7 +479,10 @@ START
389
479
  # source_lang is symbol
390
480
  # make_file flag defaults to true; set to false if you do not want files to be created by this method
391
481
  # force_file flag is false; set to true if you wish to overwrite matching destination files (use with caution!)
392
- def generate(dest_lang, source, source_lang, make_file = true, force_file = false)
482
+ # lenient_mode flag is true; if the SON contains different objects with the same name (e.g. "data") then these will be treated
483
+ # as different objects with a _1, _2, etc. suffix. If this flag is false and these different objects are present, then errors will occur
484
+ # custom_file_path is nil; set to an absoulte or relative path to have the new files be written to that location
485
+ def generate(dest_lang, source, source_lang, make_file = true, force_file = false, lenient_mode = true, custom_file_path = nil)
393
486
 
394
487
  error_and_exit "Please supply first argument as a Symbol" unless dest_lang.class == Symbol
395
488
 
@@ -434,16 +527,46 @@ START
434
527
  top_level_classname = generate_top_level_name
435
528
  output_classes = generate_output_classes(hash, top_level_classname).flatten # returns an array
436
529
 
530
+ # Set the directory that the files will be written into
531
+ if custom_file_path
532
+ # This caters for both absolute & relative file paths
533
+ file_path = File.absolute_path(custom_file_path)
534
+ else
535
+ file_path = Dir.getwd
536
+ end
537
+
538
+ # Track the names of the classes/files we have written so far
539
+ written_file_names = []
540
+
437
541
  if make_file
438
542
  output_classes.each do |out|
439
543
  name = out[:name_with_ext]
544
+ # Check the name against the files we have already written
545
+ if written_file_names.include?(name)
546
+ if lenient_mode
547
+ # Let us increment the name, e.g. "data.rb" -> "data_1.rb", "data_2.rb", etc.
548
+ increment = 1
549
+ new_name = name.gsub(@extension, "_#{increment}#{@extension}")
550
+ while written_file_names.include?(new_name)
551
+ increment += 1
552
+ new_name = name.gsub(@extension, "_#{increment}#{@extension}")
553
+ end
554
+ name = new_name
555
+ else
556
+ message = "Want to generate output file #{name}, but a file with that name has already been written by this process. Your SON structure contains 2+ different classes with the same name"
557
+ error_and_exit(message)
558
+ end
559
+ end
560
+
561
+ filename = file_path + File::SEPARATOR + name
440
562
  contents = out[:contents]
441
563
  unless force_file
442
564
  error_and_exit "Want to generate output file #{name}, but that file already exists" if File.exists?(name)
443
565
  end
444
- File.open(name, "w+") do |f|
566
+ File.open(filename, "w+") do |f|
445
567
  f.puts contents
446
568
  end
569
+ written_file_names << name
447
570
  puts "Wrote out file #{name}"
448
571
  end
449
572
 
@@ -19,7 +19,7 @@ class TestEx < Test::Unit::TestCase
19
19
 
20
20
  address_filename = "address.rb"
21
21
  top_level_filename = "generated_from_json.rb"
22
- phonenumbers_filename = "phonenumbers.rb"
22
+ phonenumbers_filename = "phone_numbers.rb"
23
23
 
24
24
  expected_address = File.readlines(address_filename).join.chomp # trim off any trailing whitespace (irrelevent for this test)
25
25
  expected_example = File.readlines(top_level_filename).join.chomp # trim off any trailing whitespace (irrelevent for this test)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: class_from_son
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Morrisby
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-20 00:00:00.000000000 Z
11
+ date: 2021-07-07 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: This gem will attempt to generate code of a class of an object representing
14
14
  the contents of a Serialised-Object-Notation (SON) string (or file). E.g. it will
@@ -22,7 +22,7 @@ files:
22
22
  - README.md
23
23
  - lib/class_from_SON.rb
24
24
  - test/test_class_from_son.rb
25
- homepage: https://rubygems.org/gems/class_from_son
25
+ homepage: https://github.com/RMorrisby/class_from_son
26
26
  licenses:
27
27
  - MIT
28
28
  metadata: {}