moblues 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.
- 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
|