schematic 0.0.1
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/.gitignore +9 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/LICENSE +19 -0
- data/README.rdoc +3 -0
- data/Rakefile +12 -0
- data/lib/schematic.rb +15 -0
- data/lib/schematic/serializers/xsd.rb +115 -0
- data/lib/schematic/version.rb +3 -0
- data/schematic.gemspec +28 -0
- data/spec/schematic_serializers_xsd_spec.rb +172 -0
- data/spec/spec_helper.rb +9 -0
- metadata +134 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.2-p136@schematic
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010-11 Case Commons, LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rspec/core'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
require 'bundler'
|
6
|
+
Bundler::GemHelper.install_tasks
|
7
|
+
|
8
|
+
task :default => :spec
|
9
|
+
|
10
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
11
|
+
RSpec::Core::RakeTask.new(:spec)
|
12
|
+
|
data/lib/schematic.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Schematic
|
2
|
+
class InvalidClass < Exception
|
3
|
+
def message
|
4
|
+
"This class does not include ActiveModel. You cannot generate an XSD from it."
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require "builder"
|
10
|
+
|
11
|
+
require 'active_support/inflector/inflections'
|
12
|
+
require 'active_support/inflections'
|
13
|
+
require "schematic/serializers/xsd"
|
14
|
+
|
15
|
+
ActiveRecord::Base.send(:extend, Schematic::Serializers::Xsd)
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Schematic
|
2
|
+
module Serializers
|
3
|
+
module Xsd
|
4
|
+
class << self
|
5
|
+
def extended(klass)
|
6
|
+
raise InvalidClass unless klass.ancestors.include?(ActiveRecord::Base)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_xsd(options = {}, builder = nil)
|
11
|
+
if builder.nil?
|
12
|
+
output = ""
|
13
|
+
builder = Builder::XmlMarkup.new(:target => output)
|
14
|
+
builder.instruct!
|
15
|
+
builder.xs :schema, "xmlns:xs" => "http://www.w3.org/2001/XMLSchema" do |schema|
|
16
|
+
schema.xs :element, "name" => xsd_element_collection_name, "type" => xsd_type_collection_name
|
17
|
+
self.to_xsd(options, schema)
|
18
|
+
end
|
19
|
+
output
|
20
|
+
else
|
21
|
+
xsd_nested_attributes.each do |nested_attribute|
|
22
|
+
nested_attribute.klass.to_xsd(options, builder)
|
23
|
+
end
|
24
|
+
builder.xs :complexType, "name" => xsd_type_collection_name do |complex_type|
|
25
|
+
complex_type.xs :sequence do |sequence|
|
26
|
+
sequence.xs :element, "name" => xsd_element_name, "type" => xsd_type_name, "minOccurs" => "0", "maxOccurs" => "unbounded"
|
27
|
+
end
|
28
|
+
complex_type.xs :attribute, "name" => "type", "type" => "xs:string", "fixed" => "array"
|
29
|
+
end
|
30
|
+
builder.xs :complexType, "name" => xsd_type_name do |complex_type|
|
31
|
+
additional_methods = xsd_methods.merge(options[:methods] || {})
|
32
|
+
complex_type.xs :all do |all|
|
33
|
+
xsd_columns.each do |column|
|
34
|
+
next if additional_methods.keys.map(&:to_s).include?(column.name)
|
35
|
+
|
36
|
+
all.xs :element, "name" => column.name.dasherize, "minOccurs" => "0", "maxOccurs" => "1" do |field|
|
37
|
+
field.xs :complexType do |complex_type|
|
38
|
+
complex_type.xs :simpleContent do |simple_content|
|
39
|
+
simple_content.xs :extension, "base" => map_column_type_to_xsd_type(column) do |extension|
|
40
|
+
extension.xs :attribute, "name" => "type", "type" => "xs:string", "use" => "optional"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
xsd_nested_attributes.each do |nested_attribute|
|
47
|
+
all.xs :element, "name" => "#{nested_attribute.name.to_s.dasherize}-attributes", "type" => nested_attribute.klass.xsd_type_collection_name, "minOccurs" => "0", "maxOccurs" => "1"
|
48
|
+
end
|
49
|
+
additional_methods.each do |method_name, values|
|
50
|
+
method_xsd_name = method_name.to_s.dasherize
|
51
|
+
if values.present?
|
52
|
+
all.xs :element, "name" => method_xsd_name, "minOccurs" => "0", "maxOccurs" => "1" do |element|
|
53
|
+
element.xs :complexType do |complex_type|
|
54
|
+
complex_type.xs :all do |nested_all|
|
55
|
+
values.each do |value|
|
56
|
+
nested_all.xs :element, "name" => value.to_s.dasherize, "minOccurs" => "0"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
complex_type.xs :attribute, "name" => "type", "type" => "xs:string", "fixed" => "array", "use" => "optional"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
else
|
63
|
+
all.xs :element, "name" => method_xsd_name, "minOccurs" => "0", "maxOccurs" => "1"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
builder
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def xsd_methods
|
73
|
+
{}
|
74
|
+
end
|
75
|
+
|
76
|
+
def xsd_nested_attributes
|
77
|
+
self.reflect_on_all_associations.select do |association|
|
78
|
+
self.instance_methods.include?("#{association.name}_attributes=".to_sym) && association.options[:polymorphic] != true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def xsd_columns
|
83
|
+
self.columns
|
84
|
+
end
|
85
|
+
|
86
|
+
def map_column_type_to_xsd_type(column)
|
87
|
+
{
|
88
|
+
:integer => "xs:integer",
|
89
|
+
:float => "xs:float",
|
90
|
+
:string => "xs:string",
|
91
|
+
:text => "xs:string",
|
92
|
+
:datetime => "xs:dateTime",
|
93
|
+
:date => "xs:date",
|
94
|
+
:boolean => "xs:boolean"
|
95
|
+
}[column.type]
|
96
|
+
end
|
97
|
+
|
98
|
+
def xsd_type_name
|
99
|
+
self.name
|
100
|
+
end
|
101
|
+
|
102
|
+
def xsd_type_collection_name
|
103
|
+
xsd_type_name.pluralize
|
104
|
+
end
|
105
|
+
|
106
|
+
def xsd_element_name
|
107
|
+
self.name.underscore.dasherize
|
108
|
+
end
|
109
|
+
|
110
|
+
def xsd_element_collection_name
|
111
|
+
xsd_element_name.pluralize
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/schematic.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "schematic/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "schematic"
|
7
|
+
s.version = Schematic::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Case Commons, LLC"]
|
10
|
+
s.email = ["casecommons-dev@googlegroups.com"]
|
11
|
+
s.homepage = "https://github.com/Casecommons/schematic"
|
12
|
+
s.summary = %q{Automatic XSD generation from ActiveRecord models}
|
13
|
+
s.description = %q{Automatic XSD generation from ActiveRecord models}
|
14
|
+
|
15
|
+
s.rubyforge_project = "schematic"
|
16
|
+
|
17
|
+
s.add_dependency('activerecord', '>= 3.0.0')
|
18
|
+
s.add_dependency('builder')
|
19
|
+
s.add_development_dependency('rspec-rails', '>= 2.1')
|
20
|
+
s.add_development_dependency('with_model')
|
21
|
+
s.add_development_dependency('nokogiri')
|
22
|
+
s.add_development_dependency('sqlite3')
|
23
|
+
|
24
|
+
s.files = `git ls-files`.split("\n")
|
25
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
26
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
27
|
+
s.require_paths = ["lib"]
|
28
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Schematic::Serializers::Xsd do
|
4
|
+
before do
|
5
|
+
class EmptyModel < ActiveRecord::Base
|
6
|
+
|
7
|
+
def self.columns
|
8
|
+
[]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".extend" do
|
14
|
+
context "when the model inherits ActiveRecord::Base" do
|
15
|
+
subject { EmptyModel }
|
16
|
+
|
17
|
+
it "should allow the model to be extended" do
|
18
|
+
lambda {
|
19
|
+
subject.class_eval do
|
20
|
+
extend Schematic::Serializers::Xsd
|
21
|
+
end
|
22
|
+
}.should_not raise_error
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when the model does not inherit ActiveRecord::Base" do
|
27
|
+
subject { Object }
|
28
|
+
|
29
|
+
it "should raise an exception" do
|
30
|
+
lambda {
|
31
|
+
subject.class_eval do
|
32
|
+
extend Schematic::Serializers::Xsd
|
33
|
+
end
|
34
|
+
}.should raise_error(Schematic::InvalidClass)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe ".to_xsd" do
|
40
|
+
context "for an empty model with no attributes or validations" do
|
41
|
+
subject { EmptyModel.to_xsd }
|
42
|
+
|
43
|
+
it "should return an xsd for an array of the model" do
|
44
|
+
xsd = <<-XML
|
45
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
46
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
47
|
+
<xs:element name="empty-models" type="EmptyModels"/>
|
48
|
+
<xs:complexType name="EmptyModels">
|
49
|
+
<xs:sequence>
|
50
|
+
<xs:element name="empty-model" type="EmptyModel" minOccurs="0" maxOccurs="unbounded"/>
|
51
|
+
</xs:sequence>
|
52
|
+
<xs:attribute name="type" type="xs:string" fixed="array"/>
|
53
|
+
</xs:complexType>
|
54
|
+
<xs:complexType name="EmptyModel">
|
55
|
+
<xs:all>
|
56
|
+
</xs:all>
|
57
|
+
</xs:complexType>
|
58
|
+
</xs:schema>
|
59
|
+
XML
|
60
|
+
subject.should == sanitize_xml(xsd)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
context "for a model with attributes" do
|
66
|
+
|
67
|
+
subject { SomeModel.to_xsd }
|
68
|
+
|
69
|
+
context "for a any attribute" do
|
70
|
+
with_model :some_model do
|
71
|
+
table :id => false do |t|
|
72
|
+
t.float 'some_float'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should define the correct xsd element" do
|
77
|
+
xsd = generate_xsd_for_model(SomeModel) do
|
78
|
+
<<-XML
|
79
|
+
<xs:element name="some-float" minOccurs="0" maxOccurs="1">
|
80
|
+
<xs:complexType>
|
81
|
+
<xs:simpleContent>
|
82
|
+
<xs:extension base="xs:float">
|
83
|
+
<xs:attribute name="type" type="xs:string" use="optional"/>
|
84
|
+
</xs:extension>
|
85
|
+
</xs:simpleContent>
|
86
|
+
</xs:complexType>
|
87
|
+
</xs:element>
|
88
|
+
XML
|
89
|
+
end
|
90
|
+
|
91
|
+
subject.should == sanitize_xml(xsd)
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "additional methods" do
|
97
|
+
with_model :some_model do
|
98
|
+
table {}
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should include the additional method" do
|
102
|
+
xsd = generate_xsd_for_model(SomeModel) do
|
103
|
+
<<-XML
|
104
|
+
<xs:element name="id" minOccurs="0" maxOccurs="1">
|
105
|
+
<xs:complexType>
|
106
|
+
<xs:simpleContent>
|
107
|
+
<xs:extension base="xs:integer">
|
108
|
+
<xs:attribute name="type" type="xs:string" use="optional"/>
|
109
|
+
</xs:extension>
|
110
|
+
</xs:simpleContent>
|
111
|
+
</xs:complexType>
|
112
|
+
</xs:element>
|
113
|
+
<xs:element name="foo-bar" minOccurs="0" maxOccurs="1"/>
|
114
|
+
XML
|
115
|
+
end
|
116
|
+
|
117
|
+
SomeModel.to_xsd(:methods => {:foo_bar => nil}).should == sanitize_xml(xsd)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "nested attributes" do
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
context "with a model with validations" do
|
128
|
+
context "presence of validation" do
|
129
|
+
context "when allow blank is true" do
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
context "when allow blank is false" do
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "length validation" do
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "inclusion validation" do
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def sanitize_xml(xml)
|
150
|
+
xml.split("\n").map(&:strip).join("")
|
151
|
+
end
|
152
|
+
|
153
|
+
def generate_xsd_for_model(model)
|
154
|
+
<<-XML
|
155
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
156
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
157
|
+
<xs:element name="#{model.xsd_element_collection_name}" type="#{model.xsd_type_collection_name}"/>
|
158
|
+
<xs:complexType name="#{model.xsd_type_collection_name}">
|
159
|
+
<xs:sequence>
|
160
|
+
<xs:element name="#{model.xsd_element_name}" type="#{model.xsd_type_name}" minOccurs="0" maxOccurs="unbounded"/>
|
161
|
+
</xs:sequence>
|
162
|
+
<xs:attribute name="type" type="xs:string" fixed="array"/>
|
163
|
+
</xs:complexType>
|
164
|
+
<xs:complexType name="#{model.xsd_type_name}">
|
165
|
+
<xs:all>
|
166
|
+
#{yield}
|
167
|
+
</xs:all>
|
168
|
+
</xs:complexType>
|
169
|
+
</xs:schema>
|
170
|
+
XML
|
171
|
+
end
|
172
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: schematic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Case Commons, LLC
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-04-01 00:00:00 -04:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: activerecord
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 3.0.0
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: builder
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0"
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: rspec-rails
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "2.1"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: with_model
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: nokogiri
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
type: :development
|
70
|
+
version_requirements: *id005
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: sqlite3
|
73
|
+
prerelease: false
|
74
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
type: :development
|
81
|
+
version_requirements: *id006
|
82
|
+
description: Automatic XSD generation from ActiveRecord models
|
83
|
+
email:
|
84
|
+
- casecommons-dev@googlegroups.com
|
85
|
+
executables: []
|
86
|
+
|
87
|
+
extensions: []
|
88
|
+
|
89
|
+
extra_rdoc_files: []
|
90
|
+
|
91
|
+
files:
|
92
|
+
- .gitignore
|
93
|
+
- .rvmrc
|
94
|
+
- Gemfile
|
95
|
+
- LICENSE
|
96
|
+
- README.rdoc
|
97
|
+
- Rakefile
|
98
|
+
- lib/schematic.rb
|
99
|
+
- lib/schematic/serializers/xsd.rb
|
100
|
+
- lib/schematic/version.rb
|
101
|
+
- schematic.gemspec
|
102
|
+
- spec/schematic_serializers_xsd_spec.rb
|
103
|
+
- spec/spec_helper.rb
|
104
|
+
has_rdoc: true
|
105
|
+
homepage: https://github.com/Casecommons/schematic
|
106
|
+
licenses: []
|
107
|
+
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: "0"
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
none: false
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: "0"
|
125
|
+
requirements: []
|
126
|
+
|
127
|
+
rubyforge_project: schematic
|
128
|
+
rubygems_version: 1.6.2
|
129
|
+
signing_key:
|
130
|
+
specification_version: 3
|
131
|
+
summary: Automatic XSD generation from ActiveRecord models
|
132
|
+
test_files:
|
133
|
+
- spec/schematic_serializers_xsd_spec.rb
|
134
|
+
- spec/spec_helper.rb
|