core-data-parser 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 19f98cd6ab3d92b8adb6c9a01bfa51cf0a4a72ed
4
+ data.tar.gz: 46ee1a118980e77ec87a37be15c545e0a21bd9df
5
+ SHA512:
6
+ metadata.gz: 431ae7976f8558a480b05c0d0029fb8beb9a9482d76b8bee7bdee41ac1b10f283522fb9549dfee9f24159bd5d27997b0acdae5b05674116ceb7fdc7170222df1
7
+ data.tar.gz: af01d20a37b9d00fc95f7ea2020faeeee32006248ee0593a8f9a15bffc15a41bfcd7123f7c14083d61014eb811b922d4e209024eec787a5a9f66e64ec3c462a1
@@ -0,0 +1,39 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+ .com.apple.timemachine.supported
4
+
5
+ ## TEXTMATE
6
+ *.tmproj
7
+ tmtags
8
+
9
+ ## EMACS
10
+ *~
11
+ \#*
12
+ .\#*
13
+
14
+ ## REDCAR
15
+ .redcar
16
+
17
+ ## VIM
18
+ *.swp
19
+ *.swo
20
+
21
+ ## RUBYMINE
22
+ .idea
23
+
24
+ ## PROJECT::GENERAL
25
+ coverage
26
+ doc
27
+ pkg
28
+ .rvmrc
29
+ .bundle
30
+ .yardoc/*
31
+ dist
32
+ Gemfile.lock
33
+ tmp
34
+ /*.gem
35
+
36
+ ## Rubinius
37
+ .rbx
38
+
39
+ ## PROJECT::SPECIFIC
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012 Mattt Thompson (http://mattt.me/)
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,5 @@
1
+ ## CORE DATA PARSER
2
+
3
+ No tests or anything. Use at your own risk.
4
+
5
+ Some day it will read CoreData models and use them to build rails models.
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup :default, :test, :development
4
+
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ require 'rspec/core/rake_task'
8
+ RSpec::Core::RakeTask.new(:spec) do |spec|
9
+ spec.pattern = 'spec/**/*_spec.rb'
10
+ end
11
+
12
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
13
+ spec.pattern = 'spec/**/*_spec.rb'
14
+ spec.rcov = true
15
+ end
16
+
17
+ task :spec
18
+ task :default => :spec
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ $:.push File.dirname(__FILE__) + '/../lib'
3
+
4
+ require 'rubygems'
5
+ require 'core-data-parser/command'
6
+
7
+ CoreDataParser::Command.start
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "core-data-parser"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "core-data-parser"
7
+ s.authors = ["Mark Madsen"]
8
+ s.email = "growl@agileanimal.com"
9
+ s.homepage = "http://agileanimal.com"
10
+ s.version = CoreDataParser::VERSION
11
+ s.platform = Gem::Platform::RUBY
12
+ s.summary = "CoreDataParser"
13
+ s.description = "Automatically generate Active Record for Core Data models."
14
+
15
+ s.add_development_dependency "rspec", "~> 2.11.0"
16
+ s.add_development_dependency "rake", "~> 10.0.3"
17
+
18
+ s.add_dependency "nokogiri", "~> 1.5.6"
19
+ s.add_dependency "thor"
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+ s.require_paths = ["lib"]
25
+ end
@@ -0,0 +1,78 @@
1
+ require 'core-data-parser/data_model'
2
+ require 'core-data-parser/version'
3
+
4
+ module CoreDataParser
5
+ def self.parse(xcdatamodel, prefix=nil)
6
+ model = CoreDataParser::DataModel.new(xcdatamodel)
7
+
8
+ model.entities.each do |entity|
9
+
10
+ entity.name.slice!(prefix) if prefix && entity.name.start_with?(prefix)
11
+
12
+ properties ={}
13
+
14
+ entity.attributes.each do |attribute|
15
+ next if attribute.transient?
16
+
17
+ attribute.name.slice!(prefix) if prefix && attribute.name.start_with?(prefix)
18
+
19
+ type = case attribute.type
20
+ when "Integer 16" then :integer
21
+ when "Integer 32" then :integer
22
+ when "Integer 64" then :integer
23
+ when "Float" then :float
24
+ when "Double" then :float
25
+ when "Decimal" then :float
26
+ when "Date" then :datetime
27
+ when "Boolean" then :boolean
28
+ when "Binary" then :bytea
29
+ else :string
30
+ end
31
+
32
+ properties[attribute.name.to_sym] = type
33
+ end
34
+
35
+ entity.relationships.each do |relationship|
36
+ options = {
37
+ :index => true,
38
+ :null => relationship.optional?
39
+ }
40
+
41
+ if not relationship.to_many?
42
+ relationship_name = relationship.name
43
+ relationship_name.slice!(prefix) if prefix && relationship_name.start_with?(prefix)
44
+ properties["#{relationship.name}_id".to_sym] = :integer
45
+ end
46
+ end
47
+
48
+ suffix = properties.keys.map{|key| "#{key}:#{properties[key.to_sym]}"}.join(' ')
49
+ puts "bundle exec rails generate model #{entity.name} #{suffix}"
50
+ `bundle exec rails generate model #{entity.name} #{suffix}`
51
+
52
+ # After the model has been created we can generate relationships and validatations...
53
+ # entity.relationships.each do |relationship|
54
+ # options = {:class => Rack::CoreData::Models.const_get(relationship.destination.capitalize)}
55
+ #
56
+ # if relationship.to_many?
57
+ # one_to_many relationship.name.to_sym, options
58
+ # else
59
+ # many_to_one relationship.name.to_sym, options
60
+ # end
61
+ # end
62
+ #
63
+ # klass.send :define_method, :validate do
64
+ # entity.attributes.each do |attribute|
65
+ # case attribute.type
66
+ # when "Integer 16", "Integer 32", "Integer 64"
67
+ # validates_integer attribute.name
68
+ # when "Float", "Double", "Decimal"
69
+ # validates_numeric attribute.name
70
+ # when "String"
71
+ # validates_min_length attribute.minimum_value, attribute.name if attribute.minimum_value
72
+ # validates_max_length attribute.maximum_value, attribute.name if attribute.maximum_value
73
+ # end
74
+ # end
75
+ # end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,14 @@
1
+ require 'core-data-parser'
2
+ require 'thor'
3
+
4
+ module CoreDataParser
5
+ class Command < Thor
6
+ include Thor::Actions
7
+ desc "parse xcdatamodel-path", "parse a core data model and generate rails models (run from inside the app directory)."
8
+ method_option :prefix, :type => :string, :aliases => "-p", :desc => "Remove the specified prefix from models."
9
+ #method_option :template, :type => :boolean, :aliases => "-t", :desc => "Only display template that would be used"
10
+ def parse(xcdatamodel)
11
+ CoreDataParser.parse(xcdatamodel, options[:prefix])
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,36 @@
1
+ require 'nokogiri'
2
+
3
+ module CoreDataParser
4
+ class DataModel
5
+ attr_reader :name, :version, :entities
6
+
7
+ def initialize(data_model)
8
+ loop do
9
+ case data_model
10
+ when File, /^\<\?xml/
11
+ data_model = ::Nokogiri::XML(data_model) and redo
12
+ when String
13
+ case data_model
14
+ when /\.xcdatamodeld?$/
15
+ data_model = Dir[File.join(data_model, "/**/contents")].first and redo
16
+ else
17
+ data_model = ::File.read(data_model) and redo
18
+ end
19
+ when ::Nokogiri::XML::Document
20
+ break
21
+ else
22
+ raise ArgumentError
23
+ end
24
+ end
25
+
26
+ model = data_model.at_xpath('model')
27
+ @name = model['name']
28
+ @version = model['systemVersion']
29
+ @entities = model.xpath('entity').collect{|element| Entity.new(element)}
30
+ end
31
+ end
32
+ end
33
+
34
+ require 'core-data-parser/data_model/entity'
35
+ require 'core-data-parser/data_model/attribute'
36
+ require 'core-data-parser/data_model/relationship'
@@ -0,0 +1,71 @@
1
+ class CoreDataParser::DataModel
2
+ class Attribute
3
+ attr_reader :name, :type, :identifier, :version_hash_modifier, :default_value, :minimum_value, :maximum_value, :regular_expression
4
+
5
+ def initialize(attribute)
6
+ raise ArgumentError unless ::Nokogiri::XML::Element === attribute
7
+
8
+ @name = underscore_name(attribute['name'])
9
+ @type = attribute['attributeType']
10
+ @identifier = attribute['elementID']
11
+ @version_hash_modifier = attribute['versionHashModifier']
12
+
13
+ @default_value = default_value_from_string(attribute['defaultValueString'])
14
+ @minimum_value = range_value_from_string(attribute['minValueString'])
15
+ @maximum_value = range_value_from_string(attribute['maxValueString'])
16
+
17
+ @regular_expression = Regexp.new(attributes['regularExpressionString']) rescue nil
18
+
19
+ @optional = attribute['optional'] == "YES"
20
+ @transient = attribute['transient'] == "YES"
21
+ @indexed = attribute['indexed'] == "YES"
22
+ @syncable = attribute['syncable'] == "YES"
23
+ end
24
+
25
+ def to_s
26
+ [@name, @type].to_s
27
+ end
28
+
29
+ [:optional, :transient, :indexed, :syncable].each do |symbol|
30
+ define_method("#{symbol}?") {!!instance_variable_get(("@#{symbol}").intern)}
31
+ end
32
+
33
+ private
34
+
35
+ def underscore_name(name)
36
+ name.gsub(/::/, '/').
37
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
38
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
39
+ tr("-", "_").
40
+ downcase
41
+ end
42
+
43
+ def default_value_from_string(string)
44
+ return nil unless string
45
+
46
+ return case @type
47
+ when "Integer 16", "Integer 32", "Integer 64"
48
+ string.to_i
49
+ when "Float", "Decimal"
50
+ string.to_f
51
+ when "Boolean"
52
+ string == "YES"
53
+ else
54
+ string
55
+ end
56
+ end
57
+
58
+ def range_value_from_string(string)
59
+ return nil unless string
60
+
61
+ return case @type
62
+ when "Float", "Decimal"
63
+ string.to_f
64
+ when "Date"
65
+ string
66
+ else
67
+ string.to_i
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,29 @@
1
+ class CoreDataParser::DataModel
2
+ class Entity
3
+ attr_reader :name, :attributes, :relationships
4
+
5
+ def initialize(entity)
6
+ raise ArgumentError unless ::Nokogiri::XML::Element === entity
7
+
8
+ @name = entity['name']
9
+ @attributes = entity.xpath('attribute').collect{|element| Attribute.new(element)}
10
+ @relationships = entity.xpath('relationship').collect{|element| Relationship.new(element)}
11
+ end
12
+
13
+ def to_s
14
+ @name
15
+ end
16
+
17
+ private
18
+
19
+
20
+ def underscore_name(name)
21
+ name.gsub(/::/, '/').
22
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
23
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
24
+ tr("-", "_").
25
+ downcase
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,48 @@
1
+ class CoreDataParser::DataModel
2
+ class Relationship
3
+ attr_reader :name, :destination, :inverse, :deletion_rule, :min_count, :max_count
4
+
5
+ def initialize(relationship)
6
+ raise ArgumentError unless ::Nokogiri::XML::Element === relationship
7
+
8
+ @name = underscore_name(relationship['name'])
9
+ @destination = underscore_name(relationship['destinationEntity'])
10
+ @inverse = underscore_name(relationship['inverseName'])
11
+ @deletion_rule = relationship['deletionRule'].downcase.to_sym
12
+
13
+ @min_count = relationship['minCount'].to_i
14
+ @max_count = relationship['maxCount'].to_i
15
+
16
+ @to_many = relationship['toMany'] == "YES"
17
+ @optional = relationship['optional'] == "YES"
18
+ @syncable = relationship['syncable'] == "YES"
19
+ end
20
+
21
+ def to_s
22
+ @name
23
+ end
24
+
25
+ def to_many?
26
+ !!@to_many
27
+ end
28
+
29
+ def to_one?
30
+ !to_many?
31
+ end
32
+
33
+ [:optional, :syncable].each do |symbol|
34
+ define_method("#{symbol}?") {!!instance_variable_get(("@#{symbol}").intern)}
35
+ end
36
+
37
+ private
38
+
39
+
40
+ def underscore_name(name)
41
+ name.gsub(/::/, '/').
42
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
43
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
44
+ tr("-", "_").
45
+ downcase
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,4 @@
1
+ module CoreDataParser
2
+ VERSION = '0.1.1'
3
+ end
4
+
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: core-data-parser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Mark Madsen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-02-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 2.11.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 2.11.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 10.0.3
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 10.0.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 1.5.6
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.5.6
55
+ - !ruby/object:Gem::Dependency
56
+ name: thor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Automatically generate Active Record for Core Data models.
70
+ email: growl@agileanimal.com
71
+ executables:
72
+ - core-parser
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - bin/core-parser
82
+ - core-data-parser.gemspec
83
+ - lib/core-data-parser.rb
84
+ - lib/core-data-parser/command.rb
85
+ - lib/core-data-parser/data_model.rb
86
+ - lib/core-data-parser/data_model/attribute.rb
87
+ - lib/core-data-parser/data_model/entity.rb
88
+ - lib/core-data-parser/data_model/relationship.rb
89
+ - lib/core-data-parser/version.rb
90
+ homepage: http://agileanimal.com
91
+ licenses: []
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.0.0
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: CoreDataParser
113
+ test_files: []