building_sync_rails 0.1.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.
- checksums.yaml +7 -0
- data/LICENSE.txt +32 -0
- data/README.rdoc +3 -0
- data/Rakefile +37 -0
- data/WARRANTY.txt +22 -0
- data/app/assets/config/manifest.js +3 -0
- data/bin/rails +12 -0
- data/config/initializers/BuildingSync_initializer.rb +11 -0
- data/config/initializers/soap4r_ns_fix.rb +55 -0
- data/config/initializers/soap4r_xsd_datatypes_fix.rb +28 -0
- data/config/routes.rb +2 -0
- data/lib/BuildingSync.rb +33688 -0
- data/lib/BuildingSync_mapper.rb +8 -0
- data/lib/BuildingSync_mapping_registry.rb +15362 -0
- data/lib/building_sync_rails/engine.rb +15 -0
- data/lib/building_sync_rails/version.rb +3 -0
- data/lib/building_sync_rails.rb +5 -0
- data/lib/building_sync_tk/factory.rb +186 -0
- data/lib/building_sync_tk/inflector.rb +27 -0
- data/lib/building_sync_tk/memoization.rb +50 -0
- data/lib/building_sync_tk/model.rb +37 -0
- data/lib/building_sync_tk/version.rb +3 -0
- data/lib/building_sync_tk.rb +12 -0
- data/lib/tasks/building_sync_rails_tasks.rake +157 -0
- data/public/BuildingSync.xsd +16859 -0
- data/public/GreenBuildingXML_Ver6.01.xsd +7113 -0
- data/test/building_sync_rails_test.rb +7 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/config/manifest.js +3 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config/application.rb +25 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/log/development.log +24 -0
- data/test/dummy/log/test.log +48 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/integration/navigation_test.rb +8 -0
- data/test/test_helper.rb +21 -0
- metadata +226 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
module BuildingSyncRails
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
config.to_prepare do
|
4
|
+
require_relative "../../config/initializers/BuildingSync_initializer.rb"
|
5
|
+
require_relative "../../config/initializers/soap4r_ns_fix.rb"
|
6
|
+
require_relative "../../config/initializers/soap4r_xsd_datatypes_fix.rb"
|
7
|
+
|
8
|
+
require_relative "../../lib/building_sync_tk.rb"
|
9
|
+
end
|
10
|
+
|
11
|
+
# initializer "static" do |app|
|
12
|
+
# app.middleware.insert_before(::ActionDispatch::Static, ::ActionDispatch::Static, ::File.join(root, "public"))
|
13
|
+
# end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require "isomorphic/factory"
|
2
|
+
|
3
|
+
module BuildingSyncTk
|
4
|
+
# An Isomorphic factory that is specialized for the {BuildingSync} base module.
|
5
|
+
class Factory < ::Isomorphic::Factory::AbstractFactory
|
6
|
+
# @!scope class
|
7
|
+
|
8
|
+
# @!method instance
|
9
|
+
# @return [BuildingSyncTk::Factory] the singleton instance
|
10
|
+
include ::Singleton
|
11
|
+
|
12
|
+
# @!scope instance
|
13
|
+
|
14
|
+
# Private constructor.
|
15
|
+
def initialize
|
16
|
+
super(::BuildingSync)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Get +<auc:UserDefinedFields>+ for the given object.
|
20
|
+
#
|
21
|
+
# @param object [#userDefinedFields] the object
|
22
|
+
# @return [Hash<String, Array<String>>, nil] the key-value pairs as a hash or +nil+ if the given object is invalid
|
23
|
+
#
|
24
|
+
# @note The return value is a hash of arrays (not a hash) because +<auc:FieldName>+ elements are not guaranteed unique within the +<auc:UserDefinedFields>+ element.
|
25
|
+
def get_user_defined_fields(object)
|
26
|
+
object.try(:userDefinedFields).try { |building_sync_user_defined_fields|
|
27
|
+
if building_sync_user_defined_fields.is_a?(::BuildingSync::UserDefinedFields)
|
28
|
+
building_sync_user_defined_fields.inject({}) { |acc, building_sync_user_defined_fields_user_defined_field|
|
29
|
+
if building_sync_user_defined_fields_user_defined_field.is_a?(::BuildingSync::UserDefinedFields::UserDefinedField)
|
30
|
+
building_sync_user_defined_fields_user_defined_field.send(:fieldName).try(:to_s).try { |key|
|
31
|
+
building_sync_user_defined_fields_user_defined_field.send(:fieldValue).try(:to_s).try { |value|
|
32
|
+
acc[key] ||= []
|
33
|
+
acc[key] << value
|
34
|
+
}
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
acc
|
39
|
+
}
|
40
|
+
else
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
# Build an instance of the given class that represents a "link" to the given target.
|
47
|
+
#
|
48
|
+
# In BuildingSync XML, a "link" is an element with an +@IDref+ attribute. The value of the +@IDref+ attribute is the value of the +@ID+ attribute of another element.
|
49
|
+
#
|
50
|
+
# @param instance_class [Class] the class for the "link"
|
51
|
+
# @param target_instance [#xmlattr_ID] the target instance
|
52
|
+
# @param options [Hash<#to_sym, Object>] the options
|
53
|
+
# @option options [Hash<#to_sym, Object>] :attributes ({}) the attributes for the "link"
|
54
|
+
# @option options [Hash<#to_sym, #to_s>] :xmlattrs ({}) the XML attributes for the "link"
|
55
|
+
# @yieldparam instance [Object] the "link"
|
56
|
+
# @yieldreturn [void]
|
57
|
+
# @return [Object] the "link"
|
58
|
+
# @raise [Isomorphic::InvalidFactoryClass] if the given class is invalid
|
59
|
+
def link(instance_class, target_instance, **options, &block)
|
60
|
+
send(:for, instance_class, **options.merge({
|
61
|
+
attributes: (options[:attributes] || {}).merge({
|
62
|
+
xmlattr_IDref: target_instance.send(:xmlattr_ID),
|
63
|
+
}),
|
64
|
+
}), &block)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Build an instance of the given class that represents a "link" from the given source to the given target, and then assign the "link" to the source using the given method name.
|
68
|
+
#
|
69
|
+
# @param instance_method_name [#to_s] the method name
|
70
|
+
# @param instance_class [Class] the class for the "link"
|
71
|
+
# @param source_instance [#xmlattr_ID] the source instance
|
72
|
+
# @param target_instance [#xmlattr_ID] the target instance
|
73
|
+
# @param options [Hash<#to_sym, Object>] the options
|
74
|
+
# @option options [Hash<#to_sym, Object>] :attributes ({}) the attributes for the "link"
|
75
|
+
# @option options [Hash<#to_sym, #to_s>] :xmlattrs ({}) the XML attributes for the "link"
|
76
|
+
# @yieldparam instance [Object] the "link"
|
77
|
+
# @yieldreturn [void]
|
78
|
+
# @return [Object] the "link"
|
79
|
+
# @raise [Isomorphic::InvalidFactoryClass] if the given class is invalid
|
80
|
+
def link_to(instance_method_name, instance_class, source_instance, target_instance, **options, &block)
|
81
|
+
source_instance.send(:"#{instance_method_name}=", send(:link, instance_class, target_instance, **options, &block))
|
82
|
+
end
|
83
|
+
|
84
|
+
# Build an instance of the given class that represents a "link" from the given source to the given target, and then append the "link" to the "collection of links" for the source using the given method name.
|
85
|
+
#
|
86
|
+
# @param collection_method_name [#to_s] the method name
|
87
|
+
# @param collection_class [Class] the class for the "link"
|
88
|
+
# @param instance_class [Class] the class for the "link"
|
89
|
+
# @param source_instance [#xmlattr_ID] the source instance
|
90
|
+
# @param target_instance [#xmlattr_ID] the target instance
|
91
|
+
# @param options [Hash<#to_sym, Object>] the options
|
92
|
+
# @option options [Hash<#to_sym, Object>] :attributes ({}) the attributes for the "link"
|
93
|
+
# @option options [Hash<#to_sym, #to_s>] :xmlattrs ({}) the XML attributes for the "link"
|
94
|
+
# @yieldparam instance [Object] the "link"
|
95
|
+
# @yieldreturn [void]
|
96
|
+
# @return [Object] the "link"
|
97
|
+
# @raise [Isomorphic::InvalidFactoryClass] if the given class is invalid
|
98
|
+
def link_to_collection(collection_method_name, collection_class, instance_class, source_instance, target_instance, **options, &block)
|
99
|
+
collection = source_instance.send(collection_method_name) || source_instance.send(:"#{collection_method_name}=", send(:for, collection_class))
|
100
|
+
|
101
|
+
unless (instance = collection.select { |instance| instance.send(:xmlattr_IDref) == target_instance.send(:xmlattr_ID) }.first).nil?
|
102
|
+
instance
|
103
|
+
else
|
104
|
+
instance = send(:link, instance_class, target_instance, **options, &block)
|
105
|
+
|
106
|
+
collection << instance
|
107
|
+
|
108
|
+
instance
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Set +<auc:UserDefinedFields>+ for the given object.
|
113
|
+
#
|
114
|
+
# @param object [#userDefinedFields] the object
|
115
|
+
# @param hash [Hash<String, String>, nil] the key-value pairs
|
116
|
+
# @return [BuildingSync::UserDefinedFields] the +<auc:UserDefinedFields>+ instance
|
117
|
+
def set_user_defined_fields(object, hash = {})
|
118
|
+
hash.each do |key, value|
|
119
|
+
unless user_defined_field?(object, key, value)
|
120
|
+
send(:path, object, :userDefinedFields) << send(:for, ::BuildingSync::UserDefinedFields::UserDefinedField, attributes: {
|
121
|
+
fieldName: key.to_s,
|
122
|
+
fieldValue: value.to_s
|
123
|
+
})
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
object.send(:userDefinedFields)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Is a +<auc:UserDefinedField>+ present with the given key-value pair?
|
131
|
+
#
|
132
|
+
# @param object [#userDefinedFields] the object
|
133
|
+
# @param key [#to_s] the key
|
134
|
+
# @param value [#to_s] the value
|
135
|
+
# @return [Boolean] +true+ if the given key-value pair is present; otherwise, +false+
|
136
|
+
def user_defined_field?(object, key, value)
|
137
|
+
return false if key.nil? || value.nil?
|
138
|
+
|
139
|
+
send(:path, object, :userDefinedFields, try: true).try(:any?) { |building_sync_user_defined_fields_user_defined_field|
|
140
|
+
building_sync_user_defined_fields_user_defined_field.is_a?(::BuildingSync::UserDefinedFields::UserDefinedField) && building_sync_user_defined_fields_user_defined_field.send(:fieldName).try(:to_s).try(:==, key.to_s) && building_sync_user_defined_fields_user_defined_field.send(:fieldValue).try(:to_s).try(:==, value.to_s)
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
# The XML attribute names.
|
145
|
+
#
|
146
|
+
# @return [Array<#to_sym>] the XML attribute names
|
147
|
+
#
|
148
|
+
# @note In BuildingSync XML, elements may have an +@ID+ attribute.
|
149
|
+
# @see #xmlattr_ID_for
|
150
|
+
def xmlattrs
|
151
|
+
%w(ID)
|
152
|
+
end
|
153
|
+
|
154
|
+
protected
|
155
|
+
|
156
|
+
# Checks for a constant with the given name in the base module.
|
157
|
+
#
|
158
|
+
# @param base [Module] the base module
|
159
|
+
# @param klass [Class] the class
|
160
|
+
# @param const_name [#to_sym] the constant name
|
161
|
+
# @return [Class, Module, nil] the constant with the given name or +nil+ if not defined
|
162
|
+
#
|
163
|
+
# @note In BuildingSync XML, the constant may be of the given class, of the base module, or of the base module with the "Type" suffix.
|
164
|
+
def const_get(base, klass, const_name)
|
165
|
+
if klass.const_defined?(const_name)
|
166
|
+
klass.const_get(const_name)
|
167
|
+
elsif base.const_defined?(const_name)
|
168
|
+
base.const_get(const_name)
|
169
|
+
elsif base.const_defined?(:"#{const_name}Type")
|
170
|
+
base.const_get(:"#{const_name}Type")
|
171
|
+
else
|
172
|
+
nil
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Builds the value of the +@ID+ attribute for the given object.
|
177
|
+
#
|
178
|
+
# @param object [Object] the object
|
179
|
+
# @return [String] the value of the +@ID+ attribute
|
180
|
+
#
|
181
|
+
# @note Using the {Object#object_id} ensures that the return value is unique.
|
182
|
+
def xmlattr_ID_for(object)
|
183
|
+
"#{object.class.name.split("::")[-1]}-#{object.object_id}"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "isomorphic/inflector"
|
2
|
+
|
3
|
+
module BuildingSyncTk
|
4
|
+
# An Isomorphic inflector that is specialized for the {BuildingSync} base module.
|
5
|
+
class Inflector < ::Isomorphic::Inflector::AbstractInflector
|
6
|
+
# @!scope class
|
7
|
+
|
8
|
+
# @!method instance
|
9
|
+
# @return [BuildingSyncTk::Inflector] the singleton instance
|
10
|
+
include ::Singleton
|
11
|
+
|
12
|
+
# @!scope instance
|
13
|
+
|
14
|
+
# Private constructor.
|
15
|
+
def initialize
|
16
|
+
super(::BuildingSync)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @!method building_sync
|
20
|
+
# Inflect upon the given terms. Alias for {#isomorphism}.
|
21
|
+
#
|
22
|
+
# @param terms [Array<Object>] the inflectable terms
|
23
|
+
# @return [String] the inflection
|
24
|
+
# @raise [Isomorphic::InflectorError] if an inflectable term is invalid
|
25
|
+
alias_method :building_sync, :isomorphism
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "building_sync_tk/inflector"
|
2
|
+
|
3
|
+
require "isomorphic/memoization"
|
4
|
+
|
5
|
+
module BuildingSyncTk
|
6
|
+
# @see Isomorphic::Memoization
|
7
|
+
module Memoization
|
8
|
+
extend ::ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
include ::Isomorphic::Memoization
|
12
|
+
end
|
13
|
+
|
14
|
+
class_methods do
|
15
|
+
# @!scope class
|
16
|
+
|
17
|
+
# Defines finder methods and instance variables for the Active Record associations given by name.
|
18
|
+
#
|
19
|
+
# @param terms [Array<Object>] the inflectable terms
|
20
|
+
# @param association_names [Array<#to_s>] the association names
|
21
|
+
# @param options [Hash<Symbol, Object>] the options
|
22
|
+
# @option options [Array<#to_s>] :xmlattrs ([]) the XML attribute names
|
23
|
+
# @return [void]
|
24
|
+
# @raise [Isomorphic::InflectorError] if an inflectable term is invalid
|
25
|
+
def memo_building_sync_for(*args)
|
26
|
+
memo_isomorphism_for(BuildingSyncTk::Inflector.instance, *args, xmlattrs: BuildingSyncTk::Factory.instance.xmlattrs)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the memo-cahe.
|
30
|
+
#
|
31
|
+
# @return [Hash<Module, ActiveSupport::HashWithIndifferentAccess>] the memo-cache
|
32
|
+
def memo_building_sync_method_names_by_association_name
|
33
|
+
memo_isomorphism_method_names_by_association_name_for(BuildingSyncTk::Inflector.instance.base)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @!scope instance
|
38
|
+
|
39
|
+
# Find all memoized instances for the given Active Record record by XML attribute name.
|
40
|
+
#
|
41
|
+
# @param record [ActiveRecord::Base] the Active Record record
|
42
|
+
# @param options [Hash<Symbol, Object>] the options
|
43
|
+
# @option options [Array<#to_s>] :xmlattrs ([]) the XML attribute names
|
44
|
+
# @return [ActiveSupport::HashWithIndifferentAccess] the memoized instances by XML attribute name
|
45
|
+
# @raise [Isomorphic::InflectorError] if an inflectable term is invalid
|
46
|
+
def find_all_with_memo_building_sync_for(*args)
|
47
|
+
find_all_with_memo_isomorphism_for(BuildingSyncTk::Inflector.instance, *args, xmlattrs: BuildingSyncTk::Factory.instance.xmlattrs)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
|
3
|
+
require "building_sync_tk/factory"
|
4
|
+
require "building_sync_tk/inflector"
|
5
|
+
|
6
|
+
require "isomorphic/model"
|
7
|
+
|
8
|
+
module BuildingSyncTk
|
9
|
+
# @see Isomorphic::Model
|
10
|
+
module Model
|
11
|
+
extend ::ActiveSupport::Concern
|
12
|
+
|
13
|
+
included do
|
14
|
+
include ::Isomorphic::Model
|
15
|
+
end
|
16
|
+
|
17
|
+
class_methods do
|
18
|
+
# @!scope class
|
19
|
+
|
20
|
+
# Define an isomorphism for the given class and optional alias name.
|
21
|
+
#
|
22
|
+
# @param isomorphism_class [Class] the class for the isomorphism
|
23
|
+
# @param method_suffix [#to_s] the optional alias name for the isomorphism
|
24
|
+
# @param options [Hash<Symbol, Object>] the options
|
25
|
+
# @option options [Boolean] :allow_blank (false) +true+ if the root node should always return a non-+nil+ target
|
26
|
+
# @option options [Hash<Symbol, Object>] :attributes ({}) default attributes for the target
|
27
|
+
# @option options [Boolean] :collection (false) +true+ if the target is a collection
|
28
|
+
# @yieldparam node [Isomorphic::Node::Root] the root node
|
29
|
+
# @yieldreturn [void]
|
30
|
+
# @return [void]
|
31
|
+
# @raise [Isomorphic::InflectorError] if an inflectable term is invalid
|
32
|
+
def building_sync_for(*args, &block)
|
33
|
+
isomorphism_for(BuildingSyncTk::Factory.instance, BuildingSyncTk::Inflector.instance, *args, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "active_support/dependencies/autoload"
|
2
|
+
|
3
|
+
require "building_sync_tk/version"
|
4
|
+
|
5
|
+
module BuildingSyncTk
|
6
|
+
extend ::ActiveSupport::Autoload
|
7
|
+
|
8
|
+
autoload :Factory, "building_sync_tk/factory"
|
9
|
+
autoload :Inflector, "building_sync_tk/inflector"
|
10
|
+
autoload :Memoization, "building_sync_tk/memoization"
|
11
|
+
autoload :Model, "building_sync_tk/model"
|
12
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "open-uri"
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
# @return [String] the format string for an XML Schema Definition (XSD) import element
|
6
|
+
FORMAT_XSD_IMPORT_ = '<%s:import namespace="%s" schemaLocation="%s"/>'.freeze
|
7
|
+
|
8
|
+
# @return [Regexp] the regular expression for an XML Schema Definition (XSD) import element
|
9
|
+
REGEXP_XSD_IMPORT_ = ::Regexp.new([
|
10
|
+
::Regexp.escape('<'),
|
11
|
+
'([^:]+)',
|
12
|
+
::Regexp.escape(':import'),
|
13
|
+
'\s+',
|
14
|
+
::Regexp.escape('namespace="'),
|
15
|
+
'([^"]+)',
|
16
|
+
::Regexp.escape('"'),
|
17
|
+
'\s+',
|
18
|
+
::Regexp.escape('schemaLocation="'),
|
19
|
+
'([^"]+)',
|
20
|
+
::Regexp.escape('"'),
|
21
|
+
'\s*',
|
22
|
+
::Regexp.escape('/>'),
|
23
|
+
].join).freeze
|
24
|
+
|
25
|
+
# Download an XML Schema Definition (XSD) file and recursively download its dependencies.
|
26
|
+
#
|
27
|
+
# @param url [String] the URL of the XML Schema Definition (XSD) file to download
|
28
|
+
# @param verbose [Boolean] specifies the verbosity level
|
29
|
+
# @param cached_urls [Set<String>] the cache of URLs that have been downloaded
|
30
|
+
# @return [void]
|
31
|
+
def download_schema_recursive(url, verbose = true, cached_urls = ::Set.new)
|
32
|
+
if cached_urls.include?(url)
|
33
|
+
return
|
34
|
+
else
|
35
|
+
cached_urls << url
|
36
|
+
end
|
37
|
+
|
38
|
+
$stderr.puts(::Kernel.sprintf("** Download %s", url)) if verbose
|
39
|
+
|
40
|
+
s = ::URI.parse(url).open do |io|
|
41
|
+
io.read.gsub(REGEXP_XSD_IMPORT_) { |match_s|
|
42
|
+
prefix = ::Regexp.last_match[1]
|
43
|
+
namespace = ::Regexp.last_match[2]
|
44
|
+
schema_location = ::Regexp.last_match[3]
|
45
|
+
|
46
|
+
download_schema_recursive(schema_location, verbose, cached_urls)
|
47
|
+
|
48
|
+
# @note Replace the URL with the path on the local disk.
|
49
|
+
::Kernel.sprintf(FORMAT_XSD_IMPORT_, prefix, namespace, schema_location.split(::File::SEPARATOR)[-1])
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
# @note Open the new file in binary mode to avoid character encoding issues.
|
54
|
+
::File.open(::File.join("public", url.split(::File::SEPARATOR)[-1]), "wb") do |io|
|
55
|
+
io.puts(s)
|
56
|
+
end
|
57
|
+
|
58
|
+
return
|
59
|
+
end
|
60
|
+
|
61
|
+
namespace :building_sync_rails do
|
62
|
+
desc "Use BuildingSync XSD file to generate Ruby code via `xsd2ruby.rb` script."
|
63
|
+
task :xsd2ruby => :environment do
|
64
|
+
# @!attribute [r] uri_xsd_remote
|
65
|
+
# @return [String] the location of the BuildingSync XSD file on the remote nework
|
66
|
+
uri_xsd_remote = "https://github.com/BuildingSync/schema/raw/develop-v2/BuildingSync.xsd"
|
67
|
+
|
68
|
+
# @!attribute [r] options_by_local_name
|
69
|
+
# @return [Hash<String, Hash<Symbol, Array<Hash<Symbol, Object>>>>] the options by the local name of each Ruby source file
|
70
|
+
# @note Ruby source files are auto-generated by the "soap4r" gem. This data structure contains the information that is used to sanitize the auto-generated code, making it suitable for revision management.
|
71
|
+
options_by_local_name = {
|
72
|
+
"BuildingSync.rb" => {
|
73
|
+
delete_at: [
|
74
|
+
{
|
75
|
+
index: 4,
|
76
|
+
count: 2,
|
77
|
+
},
|
78
|
+
{
|
79
|
+
index: -2,
|
80
|
+
count: 2,
|
81
|
+
},
|
82
|
+
],
|
83
|
+
indent_at: [
|
84
|
+
{
|
85
|
+
first_index: 4,
|
86
|
+
last_index: -2,
|
87
|
+
count: 1,
|
88
|
+
separator: ' ',
|
89
|
+
},
|
90
|
+
],
|
91
|
+
},
|
92
|
+
"BuildingSync_mapper.rb" => {
|
93
|
+
delete_at: [
|
94
|
+
{
|
95
|
+
index: 3,
|
96
|
+
count: 2,
|
97
|
+
},
|
98
|
+
{
|
99
|
+
index: -2,
|
100
|
+
count: 2,
|
101
|
+
},
|
102
|
+
],
|
103
|
+
indent_at: [],
|
104
|
+
},
|
105
|
+
"BuildingSync_mapping_registry.rb" => {
|
106
|
+
delete_at: [
|
107
|
+
{
|
108
|
+
index: 3,
|
109
|
+
count: 2,
|
110
|
+
},
|
111
|
+
{
|
112
|
+
index: -2,
|
113
|
+
count: 2,
|
114
|
+
},
|
115
|
+
],
|
116
|
+
indent_at: [],
|
117
|
+
},
|
118
|
+
}
|
119
|
+
|
120
|
+
# @note Download the BuildingSync XSD file from the remote network and copy to the local disk.
|
121
|
+
download_schema_recursive(uri_xsd_remote, verbose)
|
122
|
+
|
123
|
+
# @note Execute the "xsd2ruby.rb" binary that is installed by the "soap4r" gem. The Ruby source files are created in the "/" directory.
|
124
|
+
::Bundler.with_clean_env do
|
125
|
+
`xsd2ruby.rb --xsd #{::File.join("public", uri_xsd_remote.split(::File::SEPARATOR)[-1])} --module_path "BuildingSync" --classdef "BuildingSync" --mapping_registry --mapper --force --quiet`
|
126
|
+
end
|
127
|
+
|
128
|
+
# @note Sanitize the contents of each Ruby source file.
|
129
|
+
options_by_local_name.each do |local_name, options|
|
130
|
+
s = ::File.open(local_name, "r") do |file|
|
131
|
+
array = file.read.split($/)
|
132
|
+
|
133
|
+
options[:delete_at].each do |hash|
|
134
|
+
hash[:count].times { array.delete_at(hash[:index]) }
|
135
|
+
end
|
136
|
+
|
137
|
+
options[:indent_at].each do |hash|
|
138
|
+
array[::Range.new(hash[:first_index], hash[:last_index], false)].each do |s|
|
139
|
+
s.gsub!(::Regexp.new("^(.*?)$"), ::Kernel.sprintf('%s\1', ::Array.new(hash[:count], hash[:separator]).join("")))
|
140
|
+
s.rstrip!
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
array.join($/)
|
145
|
+
end
|
146
|
+
|
147
|
+
::File.open(local_name, "w") do |file|
|
148
|
+
file.puts(s)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# @note Move the Ruby source files to the "lib/" directory.
|
153
|
+
options_by_local_name.keys.each do |local_name|
|
154
|
+
::FileUtils.mv(local_name, ::File.join("lib", local_name)) if ::File.exist?(local_name)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|