moblues 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.travis.yml +8 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +44 -0
- data/Rakefile +4 -0
- data/bin/moblues +5 -0
- data/lib/extensions/hash.rb +9 -0
- data/lib/moblues/cli.rb +26 -0
- data/lib/moblues/data_model/attribute.rb +15 -0
- data/lib/moblues/data_model/entity.rb +17 -0
- data/lib/moblues/data_model/relationship.rb +17 -0
- data/lib/moblues/data_model.rb +3 -0
- data/lib/moblues/generator/base.rb +65 -0
- data/lib/moblues/generator/human.rb +25 -0
- data/lib/moblues/generator/human_header.h.erb +4 -0
- data/lib/moblues/generator/human_implementation.m.erb +4 -0
- data/lib/moblues/generator/machine.rb +36 -0
- data/lib/moblues/generator/machine_header.h.erb +43 -0
- data/lib/moblues/generator/machine_implementation.m.erb +7 -0
- data/lib/moblues/generator/model.rb +23 -0
- data/lib/moblues/generator.rb +4 -0
- data/lib/moblues/reader/attribute.rb +23 -0
- data/lib/moblues/reader/entity.rb +34 -0
- data/lib/moblues/reader/model.rb +31 -0
- data/lib/moblues/reader/relationship.rb +22 -0
- data/lib/moblues/reader/type.rb +58 -0
- data/lib/moblues/reader.rb +5 -0
- data/lib/moblues/utils/model_resolver.rb +19 -0
- data/lib/moblues/version.rb +3 -0
- data/lib/moblues.rb +4 -0
- data/moblues.gemspec +33 -0
- data/spec/features/moblues_spec.rb +36 -0
- data/spec/moblues/cli_spec.rb +50 -0
- data/spec/moblues/data_model/attribute_spec.rb +30 -0
- data/spec/moblues/data_model/entity_spec.rb +48 -0
- data/spec/moblues/data_model/relationship_spec.rb +46 -0
- data/spec/moblues/generator/human_spec.rb +74 -0
- data/spec/moblues/generator/machine_spec.rb +86 -0
- data/spec/moblues/generator/model_spec.rb +27 -0
- data/spec/moblues/reader/attribute_spec.rb +22 -0
- data/spec/moblues/reader/entity_spec.rb +57 -0
- data/spec/moblues/reader/model_spec.rb +66 -0
- data/spec/moblues/reader/relationship_spec.rb +22 -0
- data/spec/moblues/reader/type_spec.rb +79 -0
- data/spec/moblues/utils/model_resolver_spec.rb +28 -0
- data/spec/resources/Model.xcdatamodeld/.xccurrentversion +8 -0
- data/spec/resources/Model.xcdatamodeld/Model 2.xcdatamodel/contents +28 -0
- data/spec/resources/Model.xcdatamodeld/Model.xcdatamodel/contents +18 -0
- data/spec/resources/expected/Author.h +4 -0
- data/spec/resources/expected/Author.m +4 -0
- data/spec/resources/expected/_Author.h +36 -0
- data/spec/resources/expected/_Author.m +9 -0
- data/spec/resources/expected/_Book.h +19 -0
- data/spec/resources/expected/_Book.m +6 -0
- data/spec/resources/expected/_Person.h +9 -0
- data/spec/resources/expected/_Person.m +6 -0
- data/spec/resources/expected/_Team.h +18 -0
- data/spec/resources/expected/_Team.m +5 -0
- data/spec/resources/expected/human/Playable.h +4 -0
- data/spec/resources/expected/human/Playable.m +4 -0
- data/spec/resources/expected/human/Playlist.h +5 -0
- data/spec/resources/expected/human/Playlist.m +4 -0
- data/spec/resources/expected/human/Track.h +4 -0
- data/spec/resources/expected/human/Track.m +4 -0
- data/spec/resources/expected/human/User.h +4 -0
- data/spec/resources/expected/human/User.m +4 -0
- data/spec/resources/expected/machine/_Playable.h +9 -0
- data/spec/resources/expected/machine/_Playable.m +6 -0
- data/spec/resources/expected/machine/_Playlist.h +28 -0
- data/spec/resources/expected/machine/_Playlist.m +6 -0
- data/spec/resources/expected/machine/_Track.h +14 -0
- data/spec/resources/expected/machine/_Track.m +7 -0
- data/spec/resources/expected/machine/_User.h +27 -0
- data/spec/resources/expected/machine/_User.m +8 -0
- data/spec/resources/factories/data_model/attribute_factory.rb +12 -0
- data/spec/resources/factories/data_model/entity_factory.rb +13 -0
- data/spec/resources/factories/data_model/relationship_factory.rb +14 -0
- data/spec/resources/fixtures.rb +34 -0
- data/spec/resources/tmp/.gitkeep +0 -0
- data/spec/resources/tmp/_Team.h +18 -0
- data/spec/resources/tmp/_Team.m +5 -0
- data/spec/resources/tmp/human/Playlist.h +5 -0
- data/spec/resources/tmp/human/Playlist.m +4 -0
- data/spec/spec_helper.rb +15 -0
- metadata +285 -0
data/moblues.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'moblues/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'moblues'
|
8
|
+
spec.version = Moblues::VERSION
|
9
|
+
spec.authors = ['Vincent Garrigues']
|
10
|
+
spec.email = ['vincent.garrigues@gmail.com']
|
11
|
+
spec.summary = 'Generates Objective-C files for entities defined in a Core Data model'
|
12
|
+
spec.description = %q{
|
13
|
+
Generates files for entities defined in a Core Data model. Inspired by mogenerator.
|
14
|
+
|
15
|
+
For each entity in the Core Data model, moblues will create two files: a machine file and a human file. The machine file will be overwritten each time and should not contain any modifications. Moblues will only create the human file if it doesn't exist.
|
16
|
+
}
|
17
|
+
spec.homepage = 'http://garriguv.io'
|
18
|
+
spec.license = 'MIT'
|
19
|
+
|
20
|
+
spec.files = `git ls-files -z`.split("\x0")
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.add_runtime_dependency 'thor', '~> 0.19'
|
26
|
+
spec.add_runtime_dependency 'plist', '~> 3.1'
|
27
|
+
|
28
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
29
|
+
spec.add_development_dependency 'rake', '~> 10.3'
|
30
|
+
spec.add_development_dependency 'rspec', '~> 3.1'
|
31
|
+
spec.add_development_dependency 'factory_girl', '~> 4.5'
|
32
|
+
spec.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.1'
|
33
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'moblues/cli'
|
3
|
+
|
4
|
+
describe 'moblues' do
|
5
|
+
subject { Moblues::CLI }
|
6
|
+
let(:perform) { subject.start([command] + options) }
|
7
|
+
|
8
|
+
describe 'generate' do
|
9
|
+
let(:command) { 'generate' }
|
10
|
+
let(:options) { %w{--model=spec/resources/Model.xcdatamodeld --human=spec/resources/tmp/human --machine=spec/resources/tmp/machine} }
|
11
|
+
|
12
|
+
after do
|
13
|
+
Fixtures.delete_tmp_files(machine_files + human_files.select { |f| !f.include?('Playlist') } )
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'generates human and machine files' do
|
17
|
+
perform
|
18
|
+
|
19
|
+
(machine_files + human_files).each do |file|
|
20
|
+
expect(Fixtures.read_file(Fixtures.generated_dir, file)).to eq(Fixtures.read_file(Fixtures.expected_dir, file))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def machine_files
|
26
|
+
entities.map{|f| "machine/_#{f}" }.map{ |f| %W(#{f}.h #{f}.m) }.flatten
|
27
|
+
end
|
28
|
+
|
29
|
+
def human_files
|
30
|
+
entities.map{|f| "human/#{f}" }.map{ |f| %W(#{f}.h #{f}.m) }.flatten
|
31
|
+
end
|
32
|
+
|
33
|
+
def entities
|
34
|
+
%w{User Playable Track Playlist}
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'moblues/cli'
|
3
|
+
|
4
|
+
describe Moblues::CLI do
|
5
|
+
subject { described_class }
|
6
|
+
let(:perform) { subject.start([command] + options, debug: true) }
|
7
|
+
|
8
|
+
context 'when command is invalid' do
|
9
|
+
let(:command) { 'invalid' }
|
10
|
+
let(:options) { [] }
|
11
|
+
|
12
|
+
it 'fails' do
|
13
|
+
expect { perform }.to raise_error
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'generate' do
|
18
|
+
let(:command) { 'generate' }
|
19
|
+
|
20
|
+
context 'when options missing' do
|
21
|
+
let(:options) { [] }
|
22
|
+
|
23
|
+
it 'fails' do
|
24
|
+
expect { perform }.to raise_error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when options given' do
|
29
|
+
let(:options) { %w{--model=model/path --human=human/path --machine=machine/path} }
|
30
|
+
|
31
|
+
let(:model_reader) { double(Moblues::Reader::Model) }
|
32
|
+
let(:model_generator) { double(Moblues::Generator::Model) }
|
33
|
+
let(:entities) { [build(:entity)] }
|
34
|
+
|
35
|
+
before do
|
36
|
+
allow(Moblues::Reader::Model).to receive(:new) { model_reader }
|
37
|
+
allow(Moblues::Generator::Model).to receive(:new) { model_generator }
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'created the directories reads the model and generates the files' do
|
41
|
+
expect(Dir).to receive(:mkdir).with('human/path').once
|
42
|
+
expect(Dir).to receive(:mkdir).with('machine/path').once
|
43
|
+
expect(model_reader).to receive(:model).with('model/path').once { entities }
|
44
|
+
expect(model_generator).to receive(:generate).with(entities).once
|
45
|
+
|
46
|
+
perform
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'moblues/data_model/attribute'
|
3
|
+
|
4
|
+
module Moblues
|
5
|
+
module DataModel
|
6
|
+
describe Attribute do
|
7
|
+
describe '#initialize' do
|
8
|
+
context 'when name and type provided' do
|
9
|
+
subject { described_class.new(name: 'attribute', type: 'type') }
|
10
|
+
|
11
|
+
it 'returns an Attribute object' do
|
12
|
+
expect(subject).to eq(Attribute.new(name: 'attribute', type: 'type'))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when name missing' do
|
17
|
+
it 'raises an assertion' do
|
18
|
+
expect { Attribute.new(type: 'type') }.to raise_exception(KeyError)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when type missing' do
|
23
|
+
it 'raises an assertion' do
|
24
|
+
expect { Attribute.new(name: 'attribute') }.to raise_exception(KeyError)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'moblues/data_model/entity'
|
3
|
+
|
4
|
+
module Moblues
|
5
|
+
module DataModel
|
6
|
+
describe Entity do
|
7
|
+
describe '#initialize' do
|
8
|
+
context 'when name, parent_entity, attributes and relationship provided' do
|
9
|
+
subject { described_class.new(name: 'AudioBook', parent_entity: 'Book', attributes: ['title'], relationships: ['author']) }
|
10
|
+
|
11
|
+
it 'returns an Entity object' do
|
12
|
+
expect(subject).to eq(Entity.new(name: 'AudioBook', parent_entity: 'Book', attributes: ['title'], relationships: ['author']))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when name missing' do
|
17
|
+
it 'raises an exception' do
|
18
|
+
expect { Entity.new(parent_entity: 'Book', attributes: ['title'], relationships: ['author']) }.to raise_exception(KeyError)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when parent_entity missing' do
|
23
|
+
subject { described_class.new(name: 'AudioBook', attributes: ['title'], relationships: ['author']) }
|
24
|
+
|
25
|
+
it 'returns an Entity with NSManagedObject parent_entity' do
|
26
|
+
expect(subject).to eq(Entity.new(name: 'AudioBook', parent_entity: 'NSManagedObject', attributes: ['title'], relationships: ['author']))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when attributes missing' do
|
31
|
+
subject { described_class.new(name: 'AudioBook', parent_entity: 'Book', relationships: ['author']) }
|
32
|
+
|
33
|
+
it 'returns an Entity with empty attributes' do
|
34
|
+
expect(subject).to eq(Entity.new(name: 'AudioBook', parent_entity: 'Book', attributes: [], relationships: ['author']))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when relationships missing' do
|
39
|
+
subject { described_class.new(name: 'AudioBook', parent_entity: 'Book', attributes: ['title']) }
|
40
|
+
|
41
|
+
it 'returns an Entity with empty relationships' do
|
42
|
+
expect(subject).to eq(Entity.new(name: 'AudioBook', parent_entity: 'Book', attributes: ['title'], relationships: []))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'moblues/data_model/relationship'
|
3
|
+
|
4
|
+
module Moblues
|
5
|
+
module DataModel
|
6
|
+
describe Relationship do
|
7
|
+
describe '#initialize' do
|
8
|
+
context 'when name, destination_entity, to_many and ordered provided' do
|
9
|
+
subject { described_class.new(name: 'relationship', destination_entity: 'entity', to_many: true, ordered: true) }
|
10
|
+
|
11
|
+
it 'returns a Relationship object' do
|
12
|
+
expect(subject).to eq(Relationship.new(name: 'relationship', destination_entity: 'entity', to_many: true, ordered: true))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when name missing' do
|
17
|
+
it 'raises an assertion' do
|
18
|
+
expect { Relationship.new(destination_entity: 'entity', to_many: true, ordered: true) }.to raise_exception(KeyError)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when destination_entity missing' do
|
23
|
+
it 'raises an assertion' do
|
24
|
+
expect { Relationship.new(name: 'relationship', to_many: true, ordered: true) }.to raise_exception(KeyError)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when to_many missing' do
|
29
|
+
subject { described_class.new(name: 'relationship', destination_entity: 'entity', ordered: true) }
|
30
|
+
|
31
|
+
it 'returns a Relationship with to_many false' do
|
32
|
+
expect(subject).to eq(Relationship.new(name: 'relationship', destination_entity: 'entity', to_many: false, ordered: true))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when ordered missing' do
|
37
|
+
subject { described_class.new(name: 'relationship', destination_entity: 'entity', to_many: true) }
|
38
|
+
|
39
|
+
it 'returns a Relationship with ordered false' do
|
40
|
+
expect(subject).to eq(Relationship.new(name: 'relationship', destination_entity: 'entity', to_many: true, ordered: false))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'moblues/generator/human'
|
3
|
+
require 'moblues/data_model'
|
4
|
+
|
5
|
+
describe Moblues::Generator::Human do
|
6
|
+
subject { described_class.new(output_dir: Fixtures.generated_dir) }
|
7
|
+
|
8
|
+
after do
|
9
|
+
Fixtures.delete_tmp_files(%w{Author.h Author.m})
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#generate' do
|
13
|
+
it 'generates a human header' do
|
14
|
+
subject.generate(entity)
|
15
|
+
|
16
|
+
expect(Fixtures.generated_file_content('Author.h')).to eq(Fixtures.expected_content('Author.h'))
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'generates a human implementation' do
|
20
|
+
subject.generate(entity)
|
21
|
+
|
22
|
+
expect(Fixtures.generated_file_content('Author.m')).to eq(Fixtures.expected_content('Author.m'))
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'if the header already exists' do
|
26
|
+
before do
|
27
|
+
File.open(File.join(Fixtures.generated_dir, 'Author.h'), 'w+') do |f|
|
28
|
+
f.write('do nothing')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'does not overwrite the header file' do
|
33
|
+
subject.generate(entity)
|
34
|
+
|
35
|
+
expect(Fixtures.generated_file_content('Author.h')).to eq('do nothing')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'if the implementation already exists' do
|
40
|
+
before do
|
41
|
+
File.open(File.join(Fixtures.generated_dir, 'Author.m'), 'w+') do |f|
|
42
|
+
f.write('do nothing')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'does not overwrite the implementation file' do
|
47
|
+
subject.generate(entity)
|
48
|
+
|
49
|
+
expect(Fixtures.generated_file_content('Author.m')).to eq('do nothing')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def entity
|
55
|
+
Moblues::DataModel::Entity.new(name: 'Author',
|
56
|
+
attributes: attributes,
|
57
|
+
relationships: relationships)
|
58
|
+
end
|
59
|
+
|
60
|
+
def attributes
|
61
|
+
[
|
62
|
+
Moblues::DataModel::Attribute.new(name: 'dob', type: :date),
|
63
|
+
Moblues::DataModel::Attribute.new(name: 'name', type: :string)
|
64
|
+
]
|
65
|
+
end
|
66
|
+
|
67
|
+
def relationships
|
68
|
+
[
|
69
|
+
Moblues::DataModel::Relationship.new(name: 'books', destination_entity: 'Book', to_many: true, ordered: true),
|
70
|
+
Moblues::DataModel::Relationship.new(name: 'essays', destination_entity: 'Book', to_many: true),
|
71
|
+
Moblues::DataModel::Relationship.new(name: 'publisher', destination_entity: 'Publisher')
|
72
|
+
]
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'moblues/generator/machine'
|
3
|
+
require 'moblues/data_model'
|
4
|
+
|
5
|
+
describe Moblues::Generator::Machine do
|
6
|
+
subject { described_class.new(output_dir: Fixtures.generated_dir) }
|
7
|
+
|
8
|
+
after do
|
9
|
+
Fixtures.delete_tmp_files(%w{_Author.h _Author.m _Person.h _Person.m _Book.h _Book.m})
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#generate' do
|
13
|
+
shared_examples_for 'machine_generator' do |name|
|
14
|
+
it 'generates a header' do
|
15
|
+
subject.generate(entity)
|
16
|
+
|
17
|
+
expect(Fixtures.generated_file_content(header(name))).to eq(Fixtures.expected_content(header(name)))
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'generates an implementation' do
|
21
|
+
subject.generate(entity)
|
22
|
+
|
23
|
+
expect(Fixtures.generated_file_content(implementation(name))).to eq(Fixtures.expected_content(implementation(name)))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with a complex entity' do
|
28
|
+
let(:entity) { Moblues::DataModel::Entity.new(name: 'Author',
|
29
|
+
parent_entity: 'Person',
|
30
|
+
attributes: attributes,
|
31
|
+
relationships: relationships) }
|
32
|
+
let(:attributes) {[
|
33
|
+
Moblues::DataModel::Attribute.new(name: 'dob', type: :date),
|
34
|
+
Moblues::DataModel::Attribute.new(name: 'name', type: :string)
|
35
|
+
]}
|
36
|
+
let(:relationships) {[
|
37
|
+
Moblues::DataModel::Relationship.new(name: 'books', destination_entity: 'Book', to_many: true, ordered: true),
|
38
|
+
Moblues::DataModel::Relationship.new(name: 'essays', destination_entity: 'Book', to_many: true),
|
39
|
+
Moblues::DataModel::Relationship.new(name: 'publisher', destination_entity: 'Publisher')
|
40
|
+
]}
|
41
|
+
|
42
|
+
it_behaves_like 'machine_generator', 'Author'
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with an entity without relationships' do
|
46
|
+
let(:entity) { Moblues::DataModel::Entity.new(name: 'Person',
|
47
|
+
attributes: [Moblues::DataModel::Attribute.new(name: 'name', type: :string),
|
48
|
+
Moblues::DataModel::Attribute.new(name: 'dob', type: :date)]) }
|
49
|
+
|
50
|
+
it_behaves_like 'machine_generator', 'Person'
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with an entity with attributes, relationships but NO forward declaration' do
|
54
|
+
let(:entity) { Moblues::DataModel::Entity.new(name: 'Book',
|
55
|
+
attributes: attributes,
|
56
|
+
relationships: relationships) }
|
57
|
+
let(:attributes) {[
|
58
|
+
Moblues::DataModel::Attribute.new(name: 'name', type: :string)
|
59
|
+
]}
|
60
|
+
let(:relationships) {[
|
61
|
+
Moblues::DataModel::Relationship.new(name: 'editions', destination_entity: 'Edition', to_many: true)
|
62
|
+
]}
|
63
|
+
|
64
|
+
it_behaves_like 'machine_generator', 'Book'
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with an entity that has a to-many relationship an a variable name that contains capitals' do
|
68
|
+
let(:entity) { Moblues::DataModel::Entity.new(name: 'Team',
|
69
|
+
attributes: [],
|
70
|
+
relationships: relationships) }
|
71
|
+
let(:relationships) {[
|
72
|
+
Moblues::DataModel::Relationship.new(name: 'teamMembers', destination_entity: 'Person', to_many: true)
|
73
|
+
]}
|
74
|
+
|
75
|
+
it_behaves_like 'machine_generator', 'Team'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def header(name)
|
80
|
+
"_#{name}.h"
|
81
|
+
end
|
82
|
+
|
83
|
+
def implementation(name)
|
84
|
+
"_#{name}.h"
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Moblues::Generator::Model do
|
4
|
+
describe '#generate' do
|
5
|
+
subject { described_class.new(human: human, machine: machine, human_dir: human_dir, machine_dir: machine_dir) }
|
6
|
+
|
7
|
+
let(:entities) { [build(:entity)] }
|
8
|
+
let(:entity) { entities.first }
|
9
|
+
let(:human_dir) { 'human/dir'}
|
10
|
+
let(:machine_dir) { 'machine/dir'}
|
11
|
+
|
12
|
+
let(:human) { double(Moblues::Generator::Human) }
|
13
|
+
let(:machine) { double(Moblues::Generator::Machine) }
|
14
|
+
|
15
|
+
before do
|
16
|
+
allow(Moblues::Generator::Human).to receive(:new).with(output_dir: human_dir) { human }
|
17
|
+
allow(Moblues::Generator::Machine).to receive(:new).with(output_dir: machine_dir) { machine }
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'generates the human and machine files' do
|
21
|
+
expect(human).to receive(:generate).with(entity).once
|
22
|
+
expect(machine).to receive(:generate).with(entity).once
|
23
|
+
|
24
|
+
subject.generate(entities)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'moblues/reader/attribute'
|
3
|
+
|
4
|
+
describe Moblues::Reader::Attribute do
|
5
|
+
describe '#attribute' do
|
6
|
+
context 'when XML is valid' do
|
7
|
+
let(:xml) { REXML::Document.new('<attribute name="testName" attributeType="String"/>').elements.first }
|
8
|
+
|
9
|
+
it 'returns an Attribute object' do
|
10
|
+
expect(subject.attribute(xml)).to eq(Moblues::DataModel::Attribute.new(name: 'testName', type: :string))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when XML is invalid' do
|
15
|
+
let(:xml) { REXML::Document.new('<notAnAttribute/>').elements.first }
|
16
|
+
|
17
|
+
it 'raises an assertion' do
|
18
|
+
expect { subject.attribute(xml) }.to raise_exception
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'moblues/reader/entity'
|
3
|
+
|
4
|
+
describe Moblues::Reader::Entity do
|
5
|
+
describe '#entity' do
|
6
|
+
context 'when XML is valid' do
|
7
|
+
subject { described_class.new(attribute_reader: attribute_reader, relationship_reader: relationship_reader) }
|
8
|
+
|
9
|
+
let(:attribute_reader) { double(Moblues::Reader::Attribute) }
|
10
|
+
let(:relationship_reader) { double(Moblues::Reader::Relationship) }
|
11
|
+
let(:xml) {
|
12
|
+
xml_str = <<EOF
|
13
|
+
<entity name="Author" parentEntity="Person" syncable="YES">
|
14
|
+
<attribute name="dob" attributeType="Date" syncable="YES"/>
|
15
|
+
<attribute name="name" attributeType="String" syncable="YES"/>
|
16
|
+
<relationship name="books" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Book" inverseName="author" inverseEntity="Book" syncable="YES"/>
|
17
|
+
</entity>
|
18
|
+
EOF
|
19
|
+
REXML::Document.new(xml_str).elements.first
|
20
|
+
}
|
21
|
+
|
22
|
+
before(:each) do
|
23
|
+
allow(attribute_reader).to receive(:attribute) { build(:attribute) }
|
24
|
+
allow(relationship_reader).to receive(:relationship) { build(:relationship) }
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'maps attributes' do
|
28
|
+
expect(attribute_reader).to receive(:attribute).twice
|
29
|
+
|
30
|
+
subject.entity(xml)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'maps relationships' do
|
34
|
+
expect(relationship_reader).to receive(:relationship).once
|
35
|
+
|
36
|
+
subject.entity(xml)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'returns an Entity' do
|
40
|
+
entity = Moblues::DataModel::Entity.new(name: 'Author',
|
41
|
+
parent_entity: 'Person',
|
42
|
+
attributes: [build(:attribute), build(:attribute)],
|
43
|
+
relationships: [build(:relationship)])
|
44
|
+
|
45
|
+
expect(subject.entity(xml)).to eq(entity)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when XML is invalid' do
|
50
|
+
let(:xml) { REXML::Document.new('<notAnEntity/>').elements.first }
|
51
|
+
|
52
|
+
it 'raises an exception' do
|
53
|
+
expect { subject.entity(xml) }.to raise_exception
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'moblues/reader/model'
|
3
|
+
|
4
|
+
describe Moblues::Reader::Model do
|
5
|
+
let(:model) { build(:model) }
|
6
|
+
let(:model_resolver) { double(Moblues::Utils::ModelResolver) }
|
7
|
+
let(:entity_reader) { double(Moblues::Reader::Entity) }
|
8
|
+
let(:file_str) {
|
9
|
+
<<EOF
|
10
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
11
|
+
<model userDefinedModelVersionIdentifier="2.0" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="6252" systemVersion="14A389" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
|
12
|
+
<entity name="Author" syncable="YES">
|
13
|
+
<attribute name="dob" attributeType="Date" syncable="YES"/>
|
14
|
+
<attribute name="name" attributeType="String" syncable="YES"/>
|
15
|
+
<relationship name="books" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Book" inverseName="author" inverseEntity="Book" syncable="YES"/>
|
16
|
+
</entity>
|
17
|
+
<entity name="Book" syncable="YES">
|
18
|
+
<attribute name="numberOfPages" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
|
19
|
+
<attribute name="title" attributeType="String" syncable="YES"/>
|
20
|
+
<relationship name="author" maxCount="1" deletionRule="Nullify" destinationEntity="Author" inverseName="books" inverseEntity="Author" syncable="YES"/>
|
21
|
+
<relationship name="publisher" maxCount="1" deletionRule="Nullify" destinationEntity="Publisher" inverseName="books" inverseEntity="Publisher" syncable="YES"/>
|
22
|
+
</entity>
|
23
|
+
<entity name="Publisher" syncable="YES">
|
24
|
+
<attribute name="name" attributeType="String" syncable="YES"/>
|
25
|
+
<attribute name="website" optional="YES" attributeType="String" syncable="YES"/>
|
26
|
+
<relationship name="books" maxCount="1" deletionRule="Nullify" destinationEntity="Book" inverseName="publisher" inverseEntity="Book" syncable="YES"/>
|
27
|
+
</entity>
|
28
|
+
<elements>
|
29
|
+
<element name="Author" positionX="-281" positionY="-39" width="128" height="88"/>
|
30
|
+
<element name="Book" positionX="-54" positionY="-9" width="128" height="103"/>
|
31
|
+
<element name="Publisher" positionX="153" positionY="6" width="128" height="88"/>
|
32
|
+
</elements>
|
33
|
+
</model>
|
34
|
+
EOF
|
35
|
+
}
|
36
|
+
|
37
|
+
subject { described_class.new(resolver: model_resolver, reader: entity_reader) }
|
38
|
+
|
39
|
+
before do
|
40
|
+
allow(model_resolver).to receive(:resolve_model)
|
41
|
+
allow(entity_reader).to receive(:entity) { build(:entity) }
|
42
|
+
allow(File).to receive(:read) { file_str }
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#parse_model' do
|
46
|
+
it 'resolves the model contents' do
|
47
|
+
expect(model_resolver).to receive(:resolve_model).with('path')
|
48
|
+
|
49
|
+
subject.model('path')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'maps the model' do
|
53
|
+
expect(entity_reader).to receive(:entity).exactly(3).times
|
54
|
+
|
55
|
+
subject.model('path')
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns an array of entities' do
|
59
|
+
expect(subject.model('path')).to eq([build(:entity), build(:entity), build(:entity)])
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'raises an assertion if path is nil' do
|
63
|
+
expect { subject.model(nil) }.to raise_exception
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'moblues/reader/relationship'
|
3
|
+
|
4
|
+
describe Moblues::Reader::Relationship do
|
5
|
+
describe '#relationship' do
|
6
|
+
context 'when XML is valid' do
|
7
|
+
let(:xml) { REXML::Document.new('<relationship name="testName" toMany="YES" destinationEntity="TestEntity" ordered="YES"/>').elements.first }
|
8
|
+
|
9
|
+
it 'returns a Relationship' do
|
10
|
+
expect(subject.relationship(xml)).to eq(Moblues::DataModel::Relationship.new(name: 'testName', destination_entity: 'TestEntity', to_many: true, ordered: true))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when XML is invalid' do
|
15
|
+
let(:xml) { REXML::Document.new('<notARelationship/>').elements.first }
|
16
|
+
|
17
|
+
it 'raises an exception' do
|
18
|
+
expect { subject.relationship(xml) }.to raise_exception
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|