kanade 0.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +14 -0
  3. data/.gitignore +12 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +7 -0
  6. data/Gemfile +4 -0
  7. data/Gemfile.lock +59 -0
  8. data/LICENSE +8 -0
  9. data/README-id.md +81 -0
  10. data/README.md +3 -0
  11. data/ROADMAP.md +11 -0
  12. data/Rakefile +23 -0
  13. data/kanade.gemspec +34 -0
  14. data/lib/kanade/all.rb +14 -0
  15. data/lib/kanade/config/default.rb +10 -0
  16. data/lib/kanade/converter/base.rb +19 -0
  17. data/lib/kanade/converter/big_decimal.rb +19 -0
  18. data/lib/kanade/converter/bool.rb +22 -0
  19. data/lib/kanade/converter/fixnum.rb +15 -0
  20. data/lib/kanade/converter/float.rb +16 -0
  21. data/lib/kanade/converter/list.rb +17 -0
  22. data/lib/kanade/converter/string.rb +17 -0
  23. data/lib/kanade/converter/symbol.rb +20 -0
  24. data/lib/kanade/converter/time.rb +25 -0
  25. data/lib/kanade/dto.rb +47 -0
  26. data/lib/kanade/engine.rb +87 -0
  27. data/lib/kanade/field_info.rb +15 -0
  28. data/lib/kanade/naming_strategy/base.rb +20 -0
  29. data/lib/kanade/naming_strategy/camel_case.rb +14 -0
  30. data/lib/kanade/naming_strategy/pascal_case.rb +12 -0
  31. data/lib/kanade/naming_strategy/snake_case.rb +16 -0
  32. data/lib/kanade/version.rb +3 -0
  33. data/lib/kanade.rb +16 -0
  34. data/spec/converter/string_spec.rb +61 -0
  35. data/spec/fixtures/catalog.rb +5 -0
  36. data/spec/fixtures/catalog_camel_case.json +19 -0
  37. data/spec/fixtures/catalog_pascal_case.json +19 -0
  38. data/spec/fixtures/product.rb +7 -0
  39. data/spec/fixtures/product_wrong.rb +7 -0
  40. data/spec/fixtures/refund_report.json +10 -0
  41. data/spec/fixtures/refund_report.rb +4 -0
  42. data/spec/fixtures/simple_product.json +7 -0
  43. data/spec/integration/class_consistency_spec.rb +49 -0
  44. data/spec/integration/simple_deserialization_integration_spec.rb +58 -0
  45. data/spec/integration/simple_serialization_integration_spec.rb +74 -0
  46. data/spec/matchers/json_matcher.rb +13 -0
  47. data/spec/naming_strategy/camel_case_spec.rb +23 -0
  48. data/spec/spec_helper.rb +106 -0
  49. data/spec/support/deep_hash_compare.rb +1 -0
  50. data/spec/support/json_minify.rb +77 -0
  51. data/spec/support/json_reader.rb +6 -0
  52. metadata +211 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dba2011d31645033e7e65d4d964804457e84a7ff
4
+ data.tar.gz: 0c762aaa23b5e9d9d491a9ab79a9bb410b1aa2fb
5
+ SHA512:
6
+ metadata.gz: bf867ed2aef8b77e996ec53596abb54cb38ddbf960862e9980b528fafa7714efe7b87fdb82d281cb83f357421dec047013630d314958b09947d4d3095c366b09
7
+ data.tar.gz: 0befa0235c6abdfe73090c88a7309b7a596a5f7cdffa170df670a479bce3019faa511068b73b30e2be87e5fe3229bf9094d2d66469cca6d8a9bdc1ff27c54c83
data/.editorconfig ADDED
@@ -0,0 +1,14 @@
1
+ # This file is for unifying the coding style for different editors and IDEs
2
+ # editorconfig.org
3
+
4
+ root = true
5
+
6
+ [*]
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+ indent_style = space
11
+ indent_size = 2
12
+
13
+ # [*.md]
14
+ # trim_trailing_whitespace = false
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ # Alphabetically by category first, then by term.
2
+ # For sorting, omit dot for dot files
3
+
4
+ # Documentation
5
+ doc
6
+ .yardoc
7
+
8
+ # IDE-specific
9
+ *.swp
10
+
11
+ # Development file
12
+ .devel
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.1
4
+ notifications:
5
+ email:
6
+ on_success: change
7
+ on_failure: change
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rack-log-viewer.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,59 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ kanade (0.1.0.beta1)
5
+ activesupport
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (5.0.0.1)
11
+ concurrent-ruby (~> 1.0, >= 1.0.2)
12
+ i18n (~> 0.7)
13
+ minitest (~> 5.1)
14
+ tzinfo (~> 1.1)
15
+ coderay (1.1.1)
16
+ concurrent-ruby (1.0.2)
17
+ diff-lcs (1.2.5)
18
+ i18n (0.7.0)
19
+ method_source (0.8.2)
20
+ minitest (5.9.0)
21
+ pry (0.10.3)
22
+ coderay (~> 1.1.0)
23
+ method_source (~> 0.8.1)
24
+ slop (~> 3.4)
25
+ rake (11.2.2)
26
+ rspec (3.5.0)
27
+ rspec-core (~> 3.5.0)
28
+ rspec-expectations (~> 3.5.0)
29
+ rspec-mocks (~> 3.5.0)
30
+ rspec-core (3.5.4)
31
+ rspec-support (~> 3.5.0)
32
+ rspec-expectations (3.5.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.5.0)
35
+ rspec-mocks (3.5.0)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.5.0)
38
+ rspec-support (3.5.0)
39
+ slop (3.6.0)
40
+ thread_safe (0.3.5)
41
+ timecop (0.8.1)
42
+ tzinfo (1.2.2)
43
+ thread_safe (~> 0.1)
44
+ yard (0.8.7.6)
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ bundler (~> 1.12)
51
+ kanade!
52
+ pry
53
+ rake
54
+ rspec (~> 3.5)
55
+ timecop
56
+ yard
57
+
58
+ BUNDLED WITH
59
+ 1.13.1
data/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2016 Muhammad Mufid Afif
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+
6
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README-id.md ADDED
@@ -0,0 +1,81 @@
1
+ # Rubygem Kanade!
2
+
3
+ > かなでる 【奏でる】
4
+ > ichidan verb → conjugation / intransitive:
5
+ > to play an instrument (esp. string instruments)
6
+
7
+ Kanade membuat lantunan kode yang harmonis antara kode Ruby
8
+ dan kode JSON. Apapun sumbernya. JSON-REST? Ayo. Hanya membaca
9
+ dari lokal? Tidak apa. Kanade menerima untaian string dari JSON
10
+ dan menerjemahkannya. Kanade pun dapat melakukan sebaliknya,
11
+ dengan menerjemahkan object transfer data ke JSON.
12
+
13
+ ## Instalasi
14
+
15
+ gem 'kanade'
16
+
17
+ ## Menggunakan Kanade
18
+
19
+ Buatlah sebuah berkas DTO, misalnya:
20
+
21
+ class List < Kanade::Dto
22
+ field :id, as: :fixnum
23
+ field :name, as: :string
24
+ field :expire_at, as: :date_time
25
+ field :price, as: :big_decimal
26
+ field :available, as: :bool
27
+ end
28
+
29
+ class Product < Kanade::Dto
30
+ field :id, as: :fixnum
31
+ field :name, as: :string
32
+ field :expire_at, as: :date_time
33
+ field :price, as: :big_decimal
34
+ field :available, as: :bool
35
+ end
36
+
37
+ Terjemahkan dari JSON:
38
+
39
+ File.read()
40
+
41
+ ## Sintaks
42
+
43
+ Untuk mendefinisikan field:
44
+
45
+ field :field_name,
46
+ as: :int, # Tipe data
47
+ from: 'TheFieldName', # Nama field di JSON apabila tidak standar
48
+ allow_null: true, # Ubah menjadi false agar Kanade melempar exception ketika bertemu nilai yang null
49
+
50
+ Tipe data yang tersedia dari asal (built-in):
51
+
52
+ - `:big_decimal`
53
+ - `:bool`
54
+ - `:fixnum`
55
+ - `:float`
56
+ - `:string`
57
+ - `:symbol`
58
+ - `:time`
59
+ - Atau, objek apapun yang meng-extend `Kanade::Dto`
60
+
61
+ ## Menambahkan Pengkonversian untuk Tipe Data Khusus
62
+
63
+ engine = Kanade::Engine.new
64
+ engine.configure |c|
65
+ c.add_converter :
66
+ end
67
+
68
+ ## Strategi Penamaan Field
69
+
70
+ Secara default, Kanade akan menggunakan mekanisme penamaan
71
+ snake_case. Tidak dapat dipungkiri bahwa penamaan ini
72
+ tidak lazim untuk beberapa landasan, misalnya di Java.
73
+ Sesuaikan saja Anda menerima dari data dengan kontrak apa.
74
+
75
+ engine = Kanade::Engine.new
76
+ engine.configure |c|
77
+ c.naming_strategy :pascal_case
78
+ end
79
+
80
+ Kanade akan otomatis mengkonversi penamaan di JSON menjadi
81
+ konvensi Ruby (`snake_case`)
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Kanade - Harmonize External API with Strong-typed Ruby Object [![Build Status](https://travis-ci.org/mufid/kanade.png)](https://travis-ci.org/mufid/kanade)
2
+
3
+ A JSON parser (intended for client). Like Gson / Jackson / JSON.NET, but for Ruby.
data/ROADMAP.md ADDED
@@ -0,0 +1,11 @@
1
+ # Roadmap
2
+
3
+ - 0.x.x --> Early generation of working Kanade
4
+ - 1.x.x --> First mature release. Expect internal API changes (Naming strategy, Converter, Configurable)
5
+ - 2.x.x --> Second mature release. Expect external API changes (Engine, DTO)
6
+
7
+
8
+ Use module?
9
+ http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
10
+
11
+ or not?
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env rake
2
+ require "rspec/core/rake_task"
3
+ require "yard"
4
+ require 'bundler'
5
+
6
+ begin
7
+ Bundler.setup :default, :development
8
+ Bundler::GemHelper.install_tasks
9
+ rescue Bundler::BundlerError => error
10
+ $stderr.puts error.message
11
+ $stderr.puts "Run `bundle install` to install missing gems"
12
+ exit error.status_code
13
+ end
14
+
15
+ RSpec::Core::RakeTask.new(:spec)
16
+
17
+ desc "Generate all of the docs"
18
+ YARD::Rake::YardocTask.new do |config|
19
+ config.files = Dir["lib/**/*.rb"]
20
+ end
21
+
22
+ desc "Default: run tests and generate docs"
23
+ task :default => [ :spec, :yard ]
data/kanade.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'kanade/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "kanade"
9
+ spec.version = Kanade::VERSION
10
+ spec.authors = ["Mufid Afif"]
11
+ spec.email = ["mufid@outlook.com"]
12
+ spec.summary = %q{ Strong-typed JSON to Ruby object serializer/deserializer }
13
+ spec.description = %q{ Strong-typed JSON to Ruby object serializer/deserializer }
14
+ spec.homepage = "https://github.com/mufid/kanade"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.start_with?("bower_components") || f.start_with?("website") || f.start_with?("bin") || f.start_with?("example")
19
+ end
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ # We use active support inflection, case conversion, and a lot more.
24
+ # Yes yes yes we need to be independent from active support, but this
25
+ # is good enough for now.
26
+ spec.add_dependency "activesupport"
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.12"
29
+ spec.add_development_dependency "rake"
30
+ spec.add_development_dependency "yard"
31
+ spec.add_development_dependency "pry"
32
+ spec.add_development_dependency "rspec", "~> 3.5"
33
+ spec.add_development_dependency "timecop"
34
+ end
data/lib/kanade/all.rb ADDED
@@ -0,0 +1,14 @@
1
+ require_relative 'engine'
2
+ require_relative 'dto'
3
+ require_relative 'config/default'
4
+ require_relative 'field_info'
5
+
6
+ require_relative 'naming_strategy/base'
7
+ (Dir["#{File.dirname(__FILE__)}/naming_strategy/*.rb"].reject{|x| x.match(/base/) }).each do |path|
8
+ require path
9
+ end
10
+
11
+ require_relative 'converter/base'
12
+ (Dir["#{File.dirname(__FILE__)}/converter/*.rb"].reject{|x| x.match(/base/) }).each do |path|
13
+ require path
14
+ end
@@ -0,0 +1,10 @@
1
+ module Kanade
2
+ class Config
3
+ def self.default
4
+ Config.new
5
+ end
6
+
7
+ attr_accessor :contract
8
+ attr_accessor :enum
9
+ end
10
+ end
@@ -0,0 +1,19 @@
1
+ module Kanade
2
+ module Converter
3
+ class Base
4
+ # STORED OBJECT --> JSON String
5
+ def serialize(term, field_info)
6
+ raise NotSupportedError
7
+ end
8
+
9
+ # JSON String / Input object --> Ruby object
10
+ def deserialize(term, field_info)
11
+ raise NotSupportedError
12
+ end
13
+
14
+ def self.configurable(name, default)
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ require 'bigdecimal'
2
+
3
+ module Kanade
4
+ module Converter
5
+ class BigDecimal < Base
6
+ Engine.register_converter!(self)
7
+
8
+ def serialize(term, _)
9
+ return nil if term.nil?
10
+ term.to_s
11
+ end
12
+ def deserialize(term, _)
13
+ return nil if term.nil?
14
+ return term if term.is_a?(BigDecimal)
15
+ ::BigDecimal.new(term)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ module Kanade
2
+ module Converter
3
+ class Bool < Base
4
+ Engine.register_converter!(self)
5
+
6
+ def serialize(term, _)
7
+ return nil if term.nil?
8
+ term.to_s
9
+ end
10
+ def deserialize(term, _)
11
+ return nil if term.nil?
12
+ return term if term.is_a?(FalseClass)
13
+ return term if term.is_a?(TrueClass)
14
+ term ? true : false
15
+ end
16
+
17
+ def from_string(term)
18
+ term.downcase === 'true'
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module Kanade
2
+ module Converter
3
+ class Fixnum < Base
4
+ Engine.register_converter!(self)
5
+ def serialize(term, _)
6
+ return nil if term.nil?
7
+ term.to_i
8
+ end
9
+ def deserialize(term, _)
10
+ return nil if term.nil?
11
+ term.to_i
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ module Kanade
2
+ module Converter
3
+ class Float < Base
4
+ Engine.register_converter!(self)
5
+ def serialize(term, _)
6
+ return nil if term.nil?
7
+ term.to_f
8
+ end
9
+ def deserialize(term, _)
10
+ return nil if term.nil?
11
+ return term if term.is_a?(Float)
12
+ term.to_f
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module Kanade
2
+ module Converter
3
+ class List < Base
4
+ Engine.register_converter!(self)
5
+
6
+ def serialize(term, _)
7
+ return nil if term.nil?
8
+ term.to_s
9
+ end
10
+ def deserialize(term, _)
11
+ return nil if term.nil?
12
+ return term if term.is_a?(BigDecimal)
13
+ ::BigDecimal.new(term)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Kanade
2
+ module Converter
3
+ class String < Base
4
+ Engine.register_converter!(self)
5
+
6
+ def serialize(term, _)
7
+ return nil if term.nil?
8
+ term.to_s
9
+ end
10
+ def deserialize(term, _)
11
+ return nil if term.nil?
12
+ return term if term.is_a?(String)
13
+ term.to_s
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ module Kanade
2
+ module Converter
3
+ class Symbol < Base
4
+ Engine.register_converter!(self)
5
+
6
+ def serialize(term, field_info)
7
+ return nil if term.nil?
8
+ term.to_s
9
+ end
10
+
11
+ def deserialize(term, field_info)
12
+ return nil if term.nil?
13
+ return term if term.is_a?(String)
14
+ term.to_s
15
+ end
16
+
17
+ configurable :symbol_contract, :camel_case
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ require 'time'
2
+
3
+ module Kanade
4
+ module Converter
5
+ class Time < Base
6
+ Engine.register_converter!(self)
7
+
8
+ def serialize(term, _)
9
+ return nil if term.nil?
10
+ term.iso8601(0)
11
+ end
12
+ def deserialize(term, _)
13
+ return nil if term.nil?
14
+ return term if term.is_a?(Time)
15
+ return term if term.is_a?(Date)
16
+ # WARNING: Parse does not really parse TZ!
17
+ # Consider using ActiveSupport?
18
+ ::Time.parse(term)
19
+ end
20
+
21
+ configurable :time_format, :iso8601
22
+ configurable :time_msec_round, 0
23
+ end
24
+ end
25
+ end
data/lib/kanade/dto.rb ADDED
@@ -0,0 +1,47 @@
1
+ module Kanade
2
+ class Dto
3
+ class_attribute :__fields
4
+ class_attribute :__definer
5
+
6
+ def self.field(name_sym, *options)
7
+ raise NotSupportedError.new('Field must be a symbol!') unless name_sym.is_a?(Symbol)
8
+ raise NotSupportedError.new('Cant use reserved name (__fields)') if name == :__fields
9
+
10
+ if self.__definer != self.name
11
+ self.__fields = array_dup(self.__fields) || []
12
+ self.__definer = self.name
13
+ end
14
+
15
+ name = name_sym.to_s.freeze
16
+ variable_ref = "@#{name}".freeze
17
+ option = options.last
18
+ converter = Engine.converter(option[:as])
19
+ key_name = option[:with]
20
+
21
+ raise Kanade::NotSupportedError.new("Converter #{option[:as]} is not registered") if converter.nil?
22
+
23
+ field = FieldInfo.new
24
+ field.converter = converter
25
+ field.key_json = key_name
26
+ field.key_ruby = name
27
+ field.sym = name_sym
28
+ field.options = option
29
+
30
+ define_method "#{name}=" do |value|
31
+ instance_variable_set(variable_ref, field.convert(value))
32
+ end
33
+
34
+ define_method "#{name}" do
35
+ instance_variable_get(variable_ref)
36
+ end
37
+
38
+ self.__fields << field
39
+ end
40
+
41
+ private
42
+ def self.array_dup(arr)
43
+ return nil if arr.nil?
44
+ arr.map(&:dup)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,87 @@
1
+ require 'json'
2
+
3
+ module Kanade
4
+ class Engine
5
+ @@converters = {}
6
+ @@name_resolvers = {}
7
+
8
+ def initialize(configuration=nil)
9
+ @config = configuration || Kanade::Config.default
10
+ end
11
+
12
+ def configure
13
+ yield @config
14
+ end
15
+
16
+ def serialize(object)
17
+ traverse_field(object).to_json
18
+ end
19
+
20
+ def traverse_field(object)
21
+ raise NotSupportedError.new("Serializer only works for Kanade::Dto, and #{object.class.name} does not extend Kanade::Dto") unless object.is_a?(Kanade::Dto)
22
+
23
+ stacks = []
24
+ result = {}
25
+ stacks += object.__fields
26
+
27
+ object.__fields.each do |field|
28
+ name = field.key_json || name_to_json(field.sym)
29
+ value = field.converter.serialize(object.send(field.sym), field)
30
+ result[name] = value
31
+ end
32
+
33
+ result
34
+ end
35
+
36
+ def deserialize(definition, json)
37
+ raise NotSupportedError.new("Can not process non-class!") unless definition.is_a?(Class)
38
+ raise NotSupportedError.new("Can not process other than DTO!") unless definition < Dto
39
+ result = definition.new
40
+ raw = JSON.parse json
41
+ result.__fields.each do |field|
42
+ name = field.key_json || name_to_json(field.sym)
43
+ value = raw[name]
44
+ next if value.nil?
45
+
46
+ result.send("#{field.key_ruby}=", value)
47
+ end
48
+ result
49
+ end
50
+
51
+ def self.register_converter!(klass)
52
+ key = klass.name.split('::').last.underscore.to_sym
53
+
54
+ return if key === :base
55
+
56
+ # We don't support multiple converter for now
57
+ raise NotSupportedError.new("#{key} registered twice") if not @@converters[key].nil?
58
+
59
+ @@converters[key] = klass.new
60
+ end
61
+
62
+ def self.register_name_resolver!(klass)
63
+ key = klass.name.split('::').last.underscore.to_sym
64
+
65
+ return if key === :base
66
+
67
+ # We don't support multiple converter for now
68
+ raise NotSupportedError.new("#{key} registered twice") if not @@name_resolvers[key].nil?
69
+
70
+ @@name_resolvers[key] = klass.new
71
+ end
72
+
73
+ def name_to_ruby(string)
74
+ strategy = @config.contract
75
+ @@name_resolvers[strategy].deserialize(string)
76
+ end
77
+
78
+ def name_to_json(sym)
79
+ strategy = @config.contract
80
+ @@name_resolvers[strategy].serialize(sym)
81
+ end
82
+
83
+ def self.converter(sym)
84
+ @@converters[sym]
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,15 @@
1
+ module Kanade
2
+ class FieldInfo
3
+ # Set the value of this field. Might
4
+ # be type casted
5
+ def convert(term)
6
+ converter.deserialize(term, self)
7
+ end
8
+
9
+ attr_accessor :converter
10
+ attr_accessor :sym
11
+ attr_accessor :key_json
12
+ attr_accessor :key_ruby
13
+ attr_accessor :options
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ module Kanade
2
+ module NamingStrategy
3
+ class Base
4
+ ##
5
+ # Ruby --> JSON
6
+ def serialize(term)
7
+ raise NotImplementedException
8
+ end
9
+ ##
10
+ # JSON --> Ruby
11
+ def deserialize(term)
12
+ raise NotImplementedException
13
+ end
14
+
15
+ def self.configurable(name)
16
+ # Do nothing for now
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ module Kanade
2
+ module NamingStrategy
3
+ class CamelCase < Base
4
+ Engine.register_name_resolver!(self)
5
+
6
+ def serialize(term)
7
+ ActiveSupport::Inflector.camelize(term, false)
8
+ end
9
+ def deserialize(term)
10
+ term.underscore.to_sym
11
+ end
12
+ end
13
+ end
14
+ end