json-schematized 0.1.0 → 0.2.0
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.
- data/Gemfile +7 -0
- data/Gemfile.lock +19 -8
- data/README.md +43 -17
- data/lib/json/schematized/base.rb +2 -11
- data/lib/json/schematized/basic_wrapper.rb +209 -0
- data/lib/json/schematized/dsl.rb +10 -4
- data/lib/json/schematized/virtus_wrapper.rb +83 -0
- data/lib/json/schematized/wrapper.rb +122 -0
- data/lib/json-schematized.rb +11 -3
- metadata +66 -74
- data/lib/json/schematized/builder.rb +0 -77
- data/lib/json/schematized_objects.rb +0 -51
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -2,22 +2,33 @@ PATH
|
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
4
|
json-schematized (0.1.0)
|
5
|
+
activesupport
|
5
6
|
multi_json (~> 1.0)
|
7
|
+
virtus
|
6
8
|
|
7
9
|
GEM
|
8
10
|
remote: http://rubygems.org/
|
9
11
|
specs:
|
12
|
+
activesupport (3.2.7)
|
13
|
+
i18n (~> 0.6)
|
14
|
+
multi_json (~> 1.0)
|
15
|
+
backports (2.6.7)
|
16
|
+
descendants_tracker (0.0.1)
|
10
17
|
diff-lcs (1.1.3)
|
11
|
-
|
18
|
+
i18n (0.6.1)
|
19
|
+
json (1.7.6)
|
12
20
|
multi_json (1.5.0)
|
13
|
-
rspec (2.
|
14
|
-
rspec-core (~> 2.
|
15
|
-
rspec-expectations (~> 2.
|
16
|
-
rspec-mocks (~> 2.
|
17
|
-
rspec-core (2.
|
18
|
-
rspec-expectations (2.
|
21
|
+
rspec (2.12.0)
|
22
|
+
rspec-core (~> 2.12.0)
|
23
|
+
rspec-expectations (~> 2.12.0)
|
24
|
+
rspec-mocks (~> 2.12.0)
|
25
|
+
rspec-core (2.12.2)
|
26
|
+
rspec-expectations (2.12.1)
|
19
27
|
diff-lcs (~> 1.1.3)
|
20
|
-
rspec-mocks (2.
|
28
|
+
rspec-mocks (2.12.1)
|
29
|
+
virtus (0.5.4)
|
30
|
+
backports (~> 2.6.1)
|
31
|
+
descendants_tracker (~> 0.0.1)
|
21
32
|
|
22
33
|
PLATFORMS
|
23
34
|
ruby
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# JSON::Schematized
|
2
2
|
|
3
|
-
|
3
|
+
[](https://travis-ci.org/abril/json-schematized)
|
4
|
+
|
5
|
+
Object builder based on JSON-Schema.
|
4
6
|
|
5
7
|
## Sample usage
|
6
8
|
|
@@ -9,24 +11,26 @@ Consider the following JSON-Schema (escaped as YAML, for better viewing):
|
|
9
11
|
```yaml
|
10
12
|
# person.yml
|
11
13
|
person:
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
name:
|
18
|
-
type: string
|
19
|
-
children:
|
20
|
-
type: array
|
21
|
-
required: true
|
22
|
-
items:
|
14
|
+
type: object
|
15
|
+
properties:
|
16
|
+
name:
|
17
|
+
type: string
|
18
|
+
birth:
|
23
19
|
type: object
|
24
20
|
properties:
|
25
21
|
name:
|
26
22
|
type: string
|
23
|
+
children:
|
24
|
+
type: array
|
25
|
+
required: true
|
26
|
+
items:
|
27
|
+
type: object
|
28
|
+
properties:
|
29
|
+
name:
|
30
|
+
type: string
|
27
31
|
```
|
28
32
|
|
29
|
-
Usage:
|
33
|
+
### Basic Wrapper Usage:
|
30
34
|
|
31
35
|
```ruby
|
32
36
|
require "json-schematized"
|
@@ -37,8 +41,30 @@ class Person < JSON::Schematized::Base
|
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
40
|
-
person = Person.new name: "John",
|
41
|
-
person.
|
42
|
-
person.
|
43
|
-
person.
|
44
|
+
person = Person.new name: "John", children: [{name: "William"}]
|
45
|
+
person.name # => "John"
|
46
|
+
person.children # => [{"name" => "William"}]
|
47
|
+
person.children.class # => Person::ChildrenCollection
|
48
|
+
person.children.first.class # => Person::Child
|
49
|
+
person.children.first.name # => "William"
|
50
|
+
```
|
51
|
+
|
52
|
+
### Virtus Wrapper Usage:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
require "json-schematized"
|
56
|
+
|
57
|
+
class Person
|
58
|
+
include JSON::Schematized
|
59
|
+
json_schema wrapper: :virtus do # block called only once
|
60
|
+
YAML.load(File.read(File.expand_path("../person.yml", __FILE__)))["person"]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
person = Person.new name: "John", children: [{name: "William"}]
|
65
|
+
person.name # => "John"
|
66
|
+
person.children # => [#<Person::Child:0x007fc990906fd0 @name="William">]
|
67
|
+
person.children.class # => Person::ChildrenCollection
|
68
|
+
person.children.first.class # => Person::Child
|
69
|
+
person.children.first.name # => "William"
|
44
70
|
```
|
@@ -1,17 +1,8 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
module JSON
|
3
3
|
module Schematized
|
4
|
-
class Base
|
5
|
-
|
6
|
-
include SchematizedObject
|
7
|
-
|
8
|
-
attr_reader :__json__
|
9
|
-
|
10
|
-
def initialize(attrs = nil)
|
11
|
-
@__json__ = {}
|
12
|
-
@__schema__ = Builder.new(self.class.json_schema)
|
13
|
-
__schema__.copy_to(__json__, attrs)
|
14
|
-
end
|
4
|
+
class Base < BasicWrapper.model_superclass
|
5
|
+
include Schematized
|
15
6
|
end
|
16
7
|
end
|
17
8
|
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require "virtus"
|
4
|
+
|
5
|
+
module JSON
|
6
|
+
module Schematized
|
7
|
+
module BasicWrapper
|
8
|
+
extend Wrapper
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
raise TypeError, "#{base.inspect} should inherits #{model_superclass}" unless base < model_superclass
|
12
|
+
base.send(:include, Models)
|
13
|
+
base.extend ClassMethods
|
14
|
+
prepare_schema!(base, base.json_schema, :complex_types)
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def attribute_set
|
19
|
+
BasicWrapper.modularize(json_schema).attribute_set
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(attrs = nil)
|
24
|
+
self.json_schema = self.class.json_schema
|
25
|
+
mass_assign!(attrs)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.modularize(json_schema)
|
29
|
+
super(json_schema) do
|
30
|
+
include BasicWrapper::SchematizedHash
|
31
|
+
|
32
|
+
def json_schema=(*args); end
|
33
|
+
|
34
|
+
def self.attribute_set
|
35
|
+
unless defined?(@attribute_set)
|
36
|
+
set = []
|
37
|
+
json_schema[:properties].each_pair do |field_name, meta|
|
38
|
+
set << Virtus::Attribute.build(field_name, BasicWrapper.meta_type(self, field_name, meta))
|
39
|
+
end
|
40
|
+
@attribute_set = Virtus::AttributeSet.new(nil, set)
|
41
|
+
end
|
42
|
+
@attribute_set
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.extend_object(base)
|
46
|
+
super
|
47
|
+
return if base.class.include? BasicWrapper::Models
|
48
|
+
class_name = :ComplexTypes
|
49
|
+
(const_defined?(class_name) ?
|
50
|
+
const_get(class_name) :
|
51
|
+
const_set(class_name, Module.new)
|
52
|
+
).tap do |klass|
|
53
|
+
unless klass.include?(self)
|
54
|
+
klass.send(:include, self)
|
55
|
+
klass.module_eval do
|
56
|
+
define_method :subclasses_namespace do
|
57
|
+
klass
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
base.extend klass
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.prepare_model(ref, field_name, model_class, json_schema)
|
68
|
+
model_class.extend BasicWrapper::ClassMethods
|
69
|
+
parent_namespace = {:ref => ref, :field => field_name.to_sym}
|
70
|
+
model_class.instance_variable_set(:@parent_namespace, parent_namespace)
|
71
|
+
def model_class.json_schema
|
72
|
+
json_schema = @parent_namespace[:ref].json_schema
|
73
|
+
meta = json_schema[:properties][@parent_namespace[:field]] || {}
|
74
|
+
meta = meta[:items] if meta[:type] == "array"
|
75
|
+
meta
|
76
|
+
end
|
77
|
+
prepare_schema!(model_class, json_schema, :complex_types)
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.model_superclass
|
81
|
+
::Hash
|
82
|
+
end
|
83
|
+
|
84
|
+
module Models
|
85
|
+
def attributes
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
def json_schema=(json_schema)
|
90
|
+
extend BasicWrapper.modularize(json_schema)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
module Collections
|
95
|
+
def coerce_members_to(member_type, json_schema)
|
96
|
+
extend BasicWrapper::SchematizedArray
|
97
|
+
self.members_type = member_type
|
98
|
+
self.members_module = BasicWrapper.modularize(json_schema)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
module SchematizedArray
|
103
|
+
attr_accessor :members_type
|
104
|
+
attr_accessor :members_module
|
105
|
+
|
106
|
+
def coerce_members_to(*args); end
|
107
|
+
|
108
|
+
def <<(value)
|
109
|
+
if members_module.json_schema[:type] == "object"
|
110
|
+
new_value = members_type.new
|
111
|
+
new_value.extend members_module
|
112
|
+
new_value.mass_assign!(value) if value.is_a?(Hash)
|
113
|
+
super(new_value)
|
114
|
+
else
|
115
|
+
super
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def mass_assign!(array)
|
120
|
+
array.each do |value|
|
121
|
+
self << value
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
module SchematizedHash
|
127
|
+
def method_missing(name, *args)
|
128
|
+
key = name.to_s
|
129
|
+
if key =~ /=\z/
|
130
|
+
key = $`.to_sym
|
131
|
+
if json_schema[:properties][key]
|
132
|
+
self[key] = args.first
|
133
|
+
else
|
134
|
+
super
|
135
|
+
end
|
136
|
+
else
|
137
|
+
read_attribute key
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def respond_to?(method_name)
|
142
|
+
json_schema[:properties].has_key?(method_name.to_sym) || super
|
143
|
+
end
|
144
|
+
|
145
|
+
def subclasses_namespace
|
146
|
+
self.class
|
147
|
+
end
|
148
|
+
|
149
|
+
def []=(key, value)
|
150
|
+
if meta = json_schema[:properties][key.to_sym]
|
151
|
+
case meta[:type]
|
152
|
+
when "array"
|
153
|
+
collection = BasicWrapper.build_collection(subclasses_namespace, key, meta[:items])
|
154
|
+
new_value = collection.class.new
|
155
|
+
new_value.coerce_members_to(collection.first, meta[:items])
|
156
|
+
new_value.mass_assign!(value) if value.is_a?(Array)
|
157
|
+
value = new_value
|
158
|
+
when "object"
|
159
|
+
model_class = BasicWrapper.build_model(subclasses_namespace, key, meta)
|
160
|
+
new_value = model_class.new
|
161
|
+
new_value.json_schema = meta
|
162
|
+
new_value.mass_assign!(value) if value.is_a?(Hash)
|
163
|
+
value = new_value
|
164
|
+
end
|
165
|
+
end
|
166
|
+
super(key.to_s, value)
|
167
|
+
end
|
168
|
+
|
169
|
+
def mass_assign!(hash)
|
170
|
+
return unless hash.is_a?(Hash)
|
171
|
+
hash.each_pair do |key, value|
|
172
|
+
self[key] = value
|
173
|
+
end
|
174
|
+
ensure
|
175
|
+
SchematizedHash.ensure_structure!(self, json_schema)
|
176
|
+
end
|
177
|
+
|
178
|
+
def read_attribute(name)
|
179
|
+
name = name.to_s
|
180
|
+
value = self[name]
|
181
|
+
if !has_key?(name) && (meta = json_schema[:properties][name.to_sym])
|
182
|
+
case meta[:type]
|
183
|
+
when "array"
|
184
|
+
self[name] = []
|
185
|
+
value = self[name]
|
186
|
+
when "object"
|
187
|
+
self[name] = {}
|
188
|
+
value = self[name]
|
189
|
+
end
|
190
|
+
end
|
191
|
+
value
|
192
|
+
end
|
193
|
+
|
194
|
+
def self.ensure_structure!(json, schema)
|
195
|
+
meta = schema[:properties]
|
196
|
+
meta.each_pair do |key, schema|
|
197
|
+
if !json.has_key?(key.to_s) && schema[:required]
|
198
|
+
json[key.to_s] = case schema[:type]
|
199
|
+
when "object" then {}
|
200
|
+
when "array" then []
|
201
|
+
else nil
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
data/lib/json/schematized/dsl.rb
CHANGED
@@ -5,16 +5,22 @@ require "multi_json"
|
|
5
5
|
module JSON
|
6
6
|
module Schematized
|
7
7
|
module DSL
|
8
|
-
def json_schema(
|
9
|
-
if instance_variable_defined?(:"@
|
10
|
-
schema = @
|
8
|
+
def json_schema(*args, &block)
|
9
|
+
if instance_variable_defined?(:"@json_schema_loader")
|
10
|
+
schema = @json_schema_loader.call
|
11
11
|
schema = MultiJson.dump(schema) unless schema.is_a?(String)
|
12
12
|
MultiJson.load(schema, :symbolize_keys => true)
|
13
13
|
else
|
14
14
|
return if self === Base
|
15
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
16
|
+
json = args.first
|
15
17
|
raise ArgumentError, "JSON or block expected" if block_given? ^ json.nil?
|
16
18
|
block = Proc.new{ json } unless block_given?
|
17
|
-
@
|
19
|
+
@json_schema_loader = block
|
20
|
+
wrapper = "#{opts.fetch(:wrapper, :basic)}_wrapper".gsub(/(?:\A_*|_)([^_])/){ $1.upcase }.to_sym
|
21
|
+
wrapper = Schematized.const_defined?(wrapper) ? Schematized.const_get(wrapper) : nil
|
22
|
+
send(:include, wrapper) if wrapper
|
23
|
+
self
|
18
24
|
end
|
19
25
|
end
|
20
26
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require "virtus"
|
4
|
+
|
5
|
+
module JSON
|
6
|
+
module Schematized
|
7
|
+
module DSL
|
8
|
+
def virtus_module
|
9
|
+
VirtusWrapper.modularize(json_schema)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module VirtusWrapper
|
14
|
+
extend Wrapper
|
15
|
+
|
16
|
+
def self.included(base)
|
17
|
+
base.send(:include, modularize(base.json_schema))
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.modularize(json_schema)
|
21
|
+
super(json_schema) do
|
22
|
+
include ::Virtus
|
23
|
+
|
24
|
+
VirtusWrapper.prepare_schema!(self, self.json_schema, :simple_types)
|
25
|
+
def self.included(base)
|
26
|
+
super
|
27
|
+
VirtusWrapper.prepare_schema!(base, json_schema, :complex_types)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.extend_object(base)
|
31
|
+
class_name = :ComplexTypes
|
32
|
+
(const_defined?(class_name) ?
|
33
|
+
const_get(class_name) :
|
34
|
+
const_set(class_name, Module.new)
|
35
|
+
).tap do |klass|
|
36
|
+
klass.send(:include, self) unless klass.include?(self)
|
37
|
+
base.extend klass
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.prepare_model(ref, field_name, model_class, json_schema)
|
44
|
+
model_class.send(:include, modularize(json_schema))
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.add_attribute!(ref, field_name, meta, kind)
|
48
|
+
opts = {}
|
49
|
+
klass = (kind.is_a?(Class) ? kind : kind.class)
|
50
|
+
if kind.is_a?(Class)
|
51
|
+
opts[:default] = klass.new if meta[:required] && kind.include?(::Virtus)
|
52
|
+
else
|
53
|
+
opts[:default] = kind.class.new
|
54
|
+
end
|
55
|
+
ref.attribute field_name, kind, opts
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.collection_superclass
|
59
|
+
Array
|
60
|
+
end
|
61
|
+
|
62
|
+
class Array < ::Array
|
63
|
+
end
|
64
|
+
|
65
|
+
module Attribute
|
66
|
+
class Array < ::Virtus::Attribute::Array
|
67
|
+
primitive VirtusWrapper::Array
|
68
|
+
default primitive.new
|
69
|
+
|
70
|
+
def new_collection
|
71
|
+
(@primitive || self.class.primitive).new
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.merge_options(type, options)
|
75
|
+
merged_options = super
|
76
|
+
klass = type.is_a?(Class) ? type : type.class
|
77
|
+
merged_options.merge(:primitive => klass)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
module Schematized
|
5
|
+
module Wrapper
|
6
|
+
def self.extended(base)
|
7
|
+
base.const_set(:Models, Module.new).send(:include, Schematized::Models)
|
8
|
+
base.const_set(:Collections, Module.new).send(:include, Schematized::Collections)
|
9
|
+
end
|
10
|
+
|
11
|
+
def modularize(json_schema, &block)
|
12
|
+
json_schema = MultiJson.dump(json_schema) unless json_schema.is_a?(String)
|
13
|
+
json_schema = MultiJson.load(json_schema, :symbolize_keys => true)
|
14
|
+
module_name = "JSD#{json_schema.hash}".gsub(/\-/, "_").to_sym # JSON-Schema Definition
|
15
|
+
if const_defined?(module_name)
|
16
|
+
const_get(module_name)
|
17
|
+
else
|
18
|
+
const_set(module_name, Module.new).tap do |m|
|
19
|
+
m.instance_variable_set(:@json_schema, json_schema)
|
20
|
+
def m.json_schema; @json_schema; end
|
21
|
+
m.send(:include, self::Models)
|
22
|
+
m.module_eval do
|
23
|
+
define_method :json_schema do
|
24
|
+
m.json_schema
|
25
|
+
end
|
26
|
+
end
|
27
|
+
m.module_eval(&block) if block_given?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def prepare_schema!(ref, json_schema, mode)
|
33
|
+
modes = {
|
34
|
+
:complex_types => 1,
|
35
|
+
:simple_types => 2,
|
36
|
+
:all_types => 3
|
37
|
+
}
|
38
|
+
mode = [modes[mode].to_i, 0].max
|
39
|
+
accept_complex_types = (modes[:complex_types] & mode) > 0
|
40
|
+
accept_simple_types = (modes[:simple_types] & mode) > 0
|
41
|
+
json_schema[:properties].each_pair do |field_name, meta|
|
42
|
+
kind = nil
|
43
|
+
case meta[:type]
|
44
|
+
when "array"
|
45
|
+
next unless accept_complex_types
|
46
|
+
collection = build_collection(ref, field_name, meta[:items])
|
47
|
+
kind = collection
|
48
|
+
when "object"
|
49
|
+
next unless accept_complex_types
|
50
|
+
model = build_model(ref, field_name, meta)
|
51
|
+
kind = model
|
52
|
+
else
|
53
|
+
next unless accept_simple_types
|
54
|
+
kind = meta_type(ref, field_name, meta)
|
55
|
+
end
|
56
|
+
add_attribute! ref, field_name, meta, kind
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_attribute!(ref, field_name, meta, kind)
|
61
|
+
end
|
62
|
+
|
63
|
+
def meta_type(ref, field_name, meta, singularize = false)
|
64
|
+
case meta[:type]
|
65
|
+
when "string"
|
66
|
+
String
|
67
|
+
when "array"
|
68
|
+
build_collection(ref, field_name, meta[:items])
|
69
|
+
when "object"
|
70
|
+
build_model(ref, field_name, meta, singularize)
|
71
|
+
else
|
72
|
+
parse_json_schema_type meta[:type]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def parse_json_schema_type(type)
|
77
|
+
Object
|
78
|
+
end
|
79
|
+
|
80
|
+
def build_class_name(field_name)
|
81
|
+
field_name.to_s.gsub(/(?:\A_*|_)([^_])/){ $1.upcase }
|
82
|
+
end
|
83
|
+
|
84
|
+
def collection_superclass
|
85
|
+
Array
|
86
|
+
end
|
87
|
+
|
88
|
+
def build_collection(ref, field_name, meta)
|
89
|
+
class_name = [build_class_name(field_name), "Collection"].join.to_sym
|
90
|
+
(ref.const_defined?(class_name) ?
|
91
|
+
ref.const_get(class_name) :
|
92
|
+
ref.const_set(class_name, Class.new(collection_superclass))
|
93
|
+
).tap do |klass|
|
94
|
+
unless klass.include?(Schematized::Collections)
|
95
|
+
klass.send(:include, self::Collections)
|
96
|
+
end
|
97
|
+
end[meta_type(ref, field_name, meta, true)]
|
98
|
+
end
|
99
|
+
|
100
|
+
def model_superclass
|
101
|
+
end
|
102
|
+
|
103
|
+
def build_model(ref, field_name, json_schema, singularize = false)
|
104
|
+
name = field_name
|
105
|
+
name = ::ActiveSupport::Inflector.singularize(field_name.to_s).to_sym if singularize
|
106
|
+
class_name = build_class_name(name).to_sym
|
107
|
+
(ref.const_defined?(class_name) ?
|
108
|
+
ref.const_get(class_name) :
|
109
|
+
ref.const_set(class_name, Class.new(*[model_superclass].compact))
|
110
|
+
).tap do |klass|
|
111
|
+
unless klass.include?(Schematized::Models)
|
112
|
+
klass.send(:include, self::Models)
|
113
|
+
prepare_model(ref, field_name, klass, json_schema)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def prepare_model(ref, field_name, model_class, json_schema)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/lib/json-schematized.rb
CHANGED
@@ -2,13 +2,21 @@
|
|
2
2
|
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__))
|
3
3
|
|
4
4
|
require "rubygems"
|
5
|
+
require "active_support"
|
5
6
|
|
6
7
|
module JSON
|
7
8
|
module Schematized
|
8
9
|
autoload :Base, "json/schematized/base"
|
9
|
-
autoload :Builder, "json/schematized/builder"
|
10
10
|
autoload :DSL, "json/schematized/dsl"
|
11
|
+
autoload :Wrapper, "json/schematized/wrapper"
|
12
|
+
autoload :BasicWrapper, "json/schematized/basic_wrapper"
|
13
|
+
autoload :VirtusWrapper, "json/schematized/virtus_wrapper"
|
14
|
+
|
15
|
+
def self.included(base)
|
16
|
+
base.extend DSL
|
17
|
+
end
|
18
|
+
|
19
|
+
module Models; end
|
20
|
+
module Collections; end
|
11
21
|
end
|
12
22
|
end
|
13
|
-
|
14
|
-
require "json/schematized_objects"
|
metadata
CHANGED
@@ -1,116 +1,108 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: json-schematized
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 0
|
10
|
-
version: 0.1.0
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Marcelo Manzan
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2013-01-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: multi_json
|
22
|
-
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &70120517130240 !ruby/object:Gem::Requirement
|
24
17
|
none: false
|
25
|
-
requirements:
|
18
|
+
requirements:
|
26
19
|
- - ~>
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70120517130240
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
requirement: &70120517129800 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70120517129800
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: virtus
|
38
|
+
requirement: &70120517129340 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
33
44
|
type: :runtime
|
34
|
-
version_requirements: *id001
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: json
|
37
45
|
prerelease: false
|
38
|
-
|
46
|
+
version_requirements: *70120517129340
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: json
|
49
|
+
requirement: &70120517128840 !ruby/object:Gem::Requirement
|
39
50
|
none: false
|
40
|
-
requirements:
|
51
|
+
requirements:
|
41
52
|
- - ~>
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
|
44
|
-
segments:
|
45
|
-
- 1
|
46
|
-
- 4
|
47
|
-
version: "1.4"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.4'
|
48
55
|
type: :development
|
49
|
-
version_requirements: *id002
|
50
|
-
- !ruby/object:Gem::Dependency
|
51
|
-
name: rspec
|
52
56
|
prerelease: false
|
53
|
-
|
57
|
+
version_requirements: *70120517128840
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rspec
|
60
|
+
requirement: &70120517128340 !ruby/object:Gem::Requirement
|
54
61
|
none: false
|
55
|
-
requirements:
|
56
|
-
- -
|
57
|
-
- !ruby/object:Gem::Version
|
58
|
-
|
59
|
-
segments:
|
60
|
-
- 2
|
61
|
-
- 6
|
62
|
-
version: "2.6"
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '2.6'
|
63
66
|
type: :development
|
64
|
-
|
65
|
-
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70120517128340
|
69
|
+
description: ''
|
66
70
|
email: manzan@gmail.com
|
67
71
|
executables: []
|
68
|
-
|
69
72
|
extensions: []
|
70
|
-
|
71
73
|
extra_rdoc_files: []
|
72
|
-
|
73
|
-
files:
|
74
|
+
files:
|
74
75
|
- lib/json/schematized/base.rb
|
75
|
-
- lib/json/schematized/
|
76
|
+
- lib/json/schematized/basic_wrapper.rb
|
76
77
|
- lib/json/schematized/dsl.rb
|
77
|
-
- lib/json/
|
78
|
+
- lib/json/schematized/virtus_wrapper.rb
|
79
|
+
- lib/json/schematized/wrapper.rb
|
78
80
|
- lib/json-schematized.rb
|
79
81
|
- README.md
|
80
82
|
- Gemfile
|
81
83
|
- Gemfile.lock
|
82
84
|
homepage: http://github.com/abril
|
83
85
|
licenses: []
|
84
|
-
|
85
86
|
post_install_message:
|
86
87
|
rdoc_options: []
|
87
|
-
|
88
|
-
require_paths:
|
88
|
+
require_paths:
|
89
89
|
- lib
|
90
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
91
|
none: false
|
92
|
-
requirements:
|
93
|
-
- -
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
|
96
|
-
|
97
|
-
- 0
|
98
|
-
version: "0"
|
99
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
97
|
none: false
|
101
|
-
requirements:
|
102
|
-
- -
|
103
|
-
- !ruby/object:Gem::Version
|
104
|
-
|
105
|
-
segments:
|
106
|
-
- 0
|
107
|
-
version: "0"
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
108
102
|
requirements: []
|
109
|
-
|
110
103
|
rubyforge_project:
|
111
104
|
rubygems_version: 1.8.15
|
112
105
|
signing_key:
|
113
106
|
specification_version: 3
|
114
107
|
summary: Template builder based on JSON-Schema
|
115
108
|
test_files: []
|
116
|
-
|
@@ -1,77 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
module JSON
|
3
|
-
module Schematized
|
4
|
-
class Builder
|
5
|
-
attr_reader :schema
|
6
|
-
|
7
|
-
def initialize(schema)
|
8
|
-
@schema = schema
|
9
|
-
end
|
10
|
-
|
11
|
-
def member?(key)
|
12
|
-
schema[:properties][key.to_sym]
|
13
|
-
end
|
14
|
-
|
15
|
-
def copy_to(json, attrs)
|
16
|
-
if json.is_a?(Array)
|
17
|
-
return unless attrs.is_a?(Array)
|
18
|
-
attrs.each{ |value| assign!(json, nil, schema, value) }
|
19
|
-
else
|
20
|
-
return unless attrs.is_a?(Hash)
|
21
|
-
attrs.each_pair do |key, value|
|
22
|
-
meta = member?(key)
|
23
|
-
assign!(json, key, meta, value) if meta
|
24
|
-
end
|
25
|
-
end
|
26
|
-
ensure_structure(json, schema)
|
27
|
-
json
|
28
|
-
end
|
29
|
-
|
30
|
-
def ensure_structure(json, schema)
|
31
|
-
case json
|
32
|
-
when Array
|
33
|
-
meta = schema[:items]
|
34
|
-
case meta && meta[:type]
|
35
|
-
when "object", "array"
|
36
|
-
json.each do |value|
|
37
|
-
ensure_structure(value, meta)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
when Hash
|
41
|
-
meta = schema[:properties]
|
42
|
-
meta.each_pair do |key, schema|
|
43
|
-
case value = json[key.to_s]
|
44
|
-
when Hash
|
45
|
-
ensure_structure(value, schema) if schema[:type] == "object"
|
46
|
-
when Array
|
47
|
-
ensure_structure(value, schema) if schema[:type] == "array"
|
48
|
-
when nil
|
49
|
-
if schema[:required]
|
50
|
-
case schema[:type]
|
51
|
-
when "object"
|
52
|
-
ensure_structure(json[key.to_s] = {}, schema)
|
53
|
-
when "array"
|
54
|
-
ensure_structure(json[key.to_s] = [], schema)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def assign!(json, key, meta, value)
|
63
|
-
case meta[:type]
|
64
|
-
when "object"
|
65
|
-
value = self.class.new(meta).copy_to({}, value)
|
66
|
-
when "array"
|
67
|
-
value = self.class.new(meta[:items]).copy_to([], value)
|
68
|
-
end
|
69
|
-
if json.is_a?(Array)
|
70
|
-
json << value
|
71
|
-
else
|
72
|
-
json[key.to_s] = value
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
module JSON
|
3
|
-
module SchematizedObject
|
4
|
-
attr_accessor :__schema__
|
5
|
-
|
6
|
-
def __json__
|
7
|
-
self
|
8
|
-
end
|
9
|
-
|
10
|
-
protected
|
11
|
-
|
12
|
-
def method_missing(name, *args)
|
13
|
-
key = name.to_s
|
14
|
-
if key =~ /=\z/
|
15
|
-
key = $`.to_sym
|
16
|
-
meta = __schema__.member?(key)
|
17
|
-
meta ? __schema__.assign!(__json__, key, meta, args.first) : super
|
18
|
-
else
|
19
|
-
read_attribute key
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def read_attribute(name)
|
24
|
-
name = name.to_s
|
25
|
-
value = __json__[name]
|
26
|
-
if !__json__.has_key?(name) && (meta = __schema__.member?(name))
|
27
|
-
case meta[:type]
|
28
|
-
when "array"
|
29
|
-
value = __json__[name] = [].tap do |array|
|
30
|
-
array.extend SchematizedArray
|
31
|
-
array.__schema__ = __schema__.class.new(meta[:items])
|
32
|
-
end
|
33
|
-
when "object"
|
34
|
-
value = __json__[name] = {}.tap do |hash|
|
35
|
-
hash.extend SchematizedObject
|
36
|
-
hash.__schema__ = __schema__.class.new(meta)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
value
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
module SchematizedArray
|
45
|
-
attr_accessor :__schema__
|
46
|
-
|
47
|
-
def __json__
|
48
|
-
self
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|