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 +4 -4
- data/README.md +14 -2
- data/lib/class_from_SON.rb +137 -14
- data/test/test_class_from_son.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86fd5ffbcbad4d75f5ba1415762ef98380c2752c0fdd523e5b903cda8fedcf35
|
4
|
+
data.tar.gz: f89cad4aad4fee289a266b774080a06db9165145e5a26fb852be1f2f6a1f647d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
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
|
```
|
data/lib/class_from_SON.rb
CHANGED
@@ -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
|
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
|
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
|
-
|
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 << "
|
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
|
-
|
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 << "
|
367
|
+
code << " h[:#{name}] = @#{name}"
|
300
368
|
end
|
301
|
-
code << "
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
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
|
|
data/test/test_class_from_son.rb
CHANGED
@@ -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 = "
|
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.
|
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:
|
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://
|
25
|
+
homepage: https://github.com/RMorrisby/class_from_son
|
26
26
|
licenses:
|
27
27
|
- MIT
|
28
28
|
metadata: {}
|