schematic 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ *.gem
2
+ *~
3
+ .DS_Store
4
+ .bundle
5
+ .idea
6
+ Gemfile.lock
7
+ doc
8
+ pkg/*
9
+ tags
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2-p136@schematic
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in schematic.gemspec
4
+ gemspec
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.
@@ -0,0 +1,3 @@
1
+ = Schematic
2
+
3
+ Automatic schema generation.
@@ -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
+
@@ -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
@@ -0,0 +1,3 @@
1
+ module Schematic
2
+ VERSION = "0.0.1"
3
+ end
@@ -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
@@ -0,0 +1,9 @@
1
+ require "active_record"
2
+ require "with_model"
3
+ require "schematic"
4
+
5
+ RSpec.configure do |config|
6
+ config.extend WithModel
7
+ end
8
+
9
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ":memory:")
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