iosgen 1.0.0 → 1.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator.xcodeproj/project.pbxproj +501 -0
  3. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  4. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator.xcodeproj/xcuserdata/fran_dev.xcuserdatad/xcschemes/iOSCleanArchitectureGenerator.xcscheme +110 -0
  5. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator.xcodeproj/xcuserdata/fran_dev.xcuserdatad/xcschemes/xcschememanagement.plist +27 -0
  6. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/AppDelegate.h +17 -0
  7. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/AppDelegate.m +45 -0
  8. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/Base.lproj/LaunchScreen.xib +41 -0
  9. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/Base.lproj/Main.storyboard +25 -0
  10. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/Images.xcassets/AppIcon.appiconset/Contents.json +68 -0
  11. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/Info.plist +47 -0
  12. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/Interactors/FJBNotificationsApiInteractor.h +9 -0
  13. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/Interactors/FJBNotificationsApiInteractor.m +15 -0
  14. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/Interactors/FJBNotificationsApiInteractorProtocol.h +9 -0
  15. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/ViewController.h +15 -0
  16. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/ViewController.m +27 -0
  17. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/ViewControllers/FJBNotificationsViewController.h +8 -0
  18. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/ViewControllers/FJBNotificationsViewController.m +31 -0
  19. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/ViewModels/FJBNotificationsViewModel.h +9 -0
  20. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/ViewModels/FJBNotificationsViewModel.m +18 -0
  21. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/ViewModels/FJBNotificationsViewModelProtocol.h +17 -0
  22. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGenerator/main.m +16 -0
  23. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGeneratorTests/Info.plist +24 -0
  24. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGeneratorTests/Interactors/FJBNotificationsApiInteractorTests.m +40 -0
  25. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGeneratorTests/ViewModels/FJBNotificationsViewModelTests.m +50 -0
  26. data/Demo/iOSCleanArchitectureGenerator/iOSCleanArchitectureGeneratorTests/iOSCleanArchitectureGeneratorTests.m +40 -0
  27. data/README.md +37 -20
  28. data/bin/iosgen +1 -1
  29. data/iosgen.gemspec +1 -1
  30. data/lib/ios_gen/generator/base_generator.rb +21 -9
  31. data/lib/ios_gen/generator/objc/action_formatter.rb +15 -2
  32. data/lib/ios_gen/generator/objc/interactor_formatter.rb +16 -11
  33. data/lib/ios_gen/generator/objc/objc_formatter.rb +4 -0
  34. data/lib/ios_gen/generator/objc/view_model_formatter.rb +18 -10
  35. data/lib/ios_gen/generator/objc/xctestcase_formatter.rb +45 -0
  36. data/lib/ios_gen/ios_gen_thor.rb +2 -1
  37. data/spec/ios_gen/generator/base_generator_spec.rb +38 -3
  38. data/spec/ios_gen/generator/objc/action_formatter_spec.rb +16 -1
  39. data/spec/ios_gen/generator/objc/interactor_formatter_spec.rb +1 -1
  40. data/spec/ios_gen/generator/objc/objc_formatter_spec.rb +0 -1
  41. data/spec/ios_gen/generator/objc/view_model_formatter_spec.rb +0 -1
  42. data/spec/ios_gen/generator/objc/xctestcase_formatter_spec.rb +91 -0
  43. data/templates/objc/Interactor.h.erb +1 -1
  44. data/templates/objc/InteractorProtocol.h.erb +2 -0
  45. data/templates/objc/ViewModel.h.erb +1 -1
  46. data/templates/objc/ViewModelProtocol.h.erb +1 -0
  47. data/templates/objc/XCTestCase.m.erb +32 -0
  48. metadata +31 -2
@@ -4,8 +4,7 @@ module IOSGen
4
4
  # Objective-C Action Formatter
5
5
  class ActionFormatter
6
6
  def generate_interface(action)
7
- result = ''
8
- result += "// #{action.description}\n" unless action.description.nil?
7
+ result = '' + add_description(action)
9
8
  result += "- (#{action.return_type})"
10
9
  result += parse_action_arguments(action) + ';'
11
10
  result
@@ -17,8 +16,22 @@ module IOSGen
17
16
  result
18
17
  end
19
18
 
19
+ def generate_test(action)
20
+ result = add_description(action) + "\n"
21
+ result += '- (void)test'
22
+ final_name = "#{action.name}".gsub(':', '')
23
+ result += final_name + 'ShouldPass' "\n{\n"
24
+ result += " // given\n // when\n // then\n"
25
+ result += " XCTFail(@\"No implemented test\");\n}\n"
26
+ result
27
+ end
28
+
20
29
  private
21
30
 
31
+ def add_description(action)
32
+ "// #{action.description}\n" unless action.description.nil?
33
+ end
34
+
22
35
  def parse_action_arguments(action)
23
36
  index = 0
24
37
  final_name = "#{action.name}".gsub(':') do
@@ -4,7 +4,7 @@ module IOSGen
4
4
  # Objective-C Interactor Formatter
5
5
  class InteractorFormatter
6
6
  # File Names Interactors
7
- attr_reader :header_file_name, :_impl_file_name
7
+ attr_reader :header_file_name, :impl_file_name
8
8
  attr_reader :protocol_file_name
9
9
  # Interactor Protocol
10
10
  attr_reader :protocol_name
@@ -40,21 +40,15 @@ module IOSGen
40
40
  end
41
41
 
42
42
  def actions_header
43
- actions = ''
44
- action_formatter = ActionFormatter.new
45
- @interactor.actions.each do |action|
46
- actions += "#{action_formatter.generate_interface(action)}\n"
43
+ loop_actions do |formatter, action|
44
+ formatter.generate_interface(action)
47
45
  end
48
- actions.chop
49
46
  end
50
47
 
51
48
  def actions_impl
52
- actions = ''
53
- action_formatter = ActionFormatter.new
54
- @interactor.actions.each do |action|
55
- actions += "#{action_formatter.generate_implementation(action)}\n"
49
+ loop_actions do |formatter, action|
50
+ formatter.generate_implementation(action)
56
51
  end
57
- actions.chop
58
52
  end
59
53
 
60
54
  def generate(&block)
@@ -62,6 +56,17 @@ module IOSGen
62
56
  block.call(header_file_name, 'templates/objc/Interactor.h.erb')
63
57
  block.call(impl_file_name, 'templates/objc/Interactor.m.erb')
64
58
  end
59
+
60
+ private
61
+
62
+ def loop_actions
63
+ actions = ''
64
+ action_formatter = ActionFormatter.new
65
+ @interactor.actions.each do |action|
66
+ actions += "#{yield(action_formatter, action)}\n"
67
+ end
68
+ actions.chop
69
+ end
65
70
  end
66
71
  end
67
72
  end
@@ -24,6 +24,10 @@ module IOSGen
24
24
  @view_controller_formatter.generate(&block)
25
25
  @view_model_formatter.generate(&block)
26
26
  end
27
+
28
+ def generate_test(&block)
29
+ @view_model_formatter.generate_test(&block)
30
+ end
27
31
  end
28
32
  end
29
33
  end
@@ -50,21 +50,15 @@ module IOSGen
50
50
  end
51
51
 
52
52
  def actions_header
53
- actions = ''
54
- action_formatter = ActionFormatter.new
55
- @view_model.actions.each do |action|
56
- actions += "#{action_formatter.generate_interface(action)}\n"
53
+ loop_actions do |formatter, action|
54
+ formatter.generate_interface(action)
57
55
  end
58
- actions.chop
59
56
  end
60
57
 
61
58
  def actions_impl
62
- actions = ''
63
- action_formatter = ActionFormatter.new
64
- @view_model.actions.each do |action|
65
- actions += "#{action_formatter.generate_implementation(action)}\n"
59
+ loop_actions do |formatter, action|
60
+ formatter.generate_implementation(action)
66
61
  end
67
- actions.chop
68
62
  end
69
63
 
70
64
  def generate(&block)
@@ -74,6 +68,11 @@ module IOSGen
74
68
  generate_interactor(&block)
75
69
  end
76
70
 
71
+ def generate_test(&block)
72
+ block.call(test_file_name, 'templates/objc/XCTestCase.m.erb')
73
+ generate_interactor_test(&block)
74
+ end
75
+
77
76
  private
78
77
 
79
78
  def generate_interactor(&block)
@@ -82,6 +81,15 @@ module IOSGen
82
81
  @interactor_formatter.generate(&block)
83
82
  end unless @view_model.interactors.nil?
84
83
  end
84
+
85
+ def loop_actions
86
+ actions = ''
87
+ action_formatter = ActionFormatter.new
88
+ @view_model.actions.each do |action|
89
+ actions += "#{yield(action_formatter, action)}\n"
90
+ end
91
+ actions.chop
92
+ end
85
93
  end
86
94
  end
87
95
  end
@@ -0,0 +1,45 @@
1
+ module IOSGen
2
+ module Generator
3
+ module Objc
4
+ # Objetive-C XCTestCase Formatter
5
+ class XctestcaseFormatter
6
+ attr_accessor :object
7
+ attr_reader :file_name, :name, :actions_impl
8
+ attr_reader :class_test_name
9
+
10
+ def file_name
11
+ "#{@object.name}Tests.m" if @object.respond_to?(:name)
12
+ end
13
+
14
+ def name
15
+ "#{@object.name}Tests" if @object.respond_to?(:name)
16
+ end
17
+
18
+ def actions_impl
19
+ loop_actions do |formatter, action|
20
+ formatter.generate_test(action)
21
+ end if @object.respond_to?(:actions)
22
+ end
23
+
24
+ def class_test_name
25
+ "#{@object.name}.h" if @object.respond_to?(:name)
26
+ end
27
+
28
+ def generate(&block)
29
+ block.call(file_name, 'templates/objc/XCTestCase.m.erb')
30
+ end
31
+
32
+ private
33
+
34
+ def loop_actions
35
+ actions = ''
36
+ action_formatter = ActionFormatter.new
37
+ @object.actions.each do |action|
38
+ actions += "#{yield(action_formatter, action)}\n"
39
+ end
40
+ actions.chop
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -7,11 +7,12 @@ class IOSGenThor < Thor
7
7
  end
8
8
 
9
9
  desc 'generate', 'Generate new code with spec file'
10
- # method_option :destination, aliases: '-d', desc: 'destination path'
10
+ option :test, aliases: '-t', desc: 'Generate unit tests'
11
11
  # method_option :languague, aliases: '-l', desc: 'objc or swift'
12
12
  def generate(file_path)
13
13
  puts file_path
14
14
  generator = IOSGen::Generator::BaseGenerator.new(file_spec: file_path)
15
15
  generator.generate
16
+ generator.generate_test if options[:test]
16
17
  end
17
18
  end
@@ -23,9 +23,9 @@ describe IOSGen::Generator::BaseGenerator do
23
23
 
24
24
  end
25
25
 
26
- describe '#Methods' do
26
+ describe 'Methods' do
27
27
 
28
- describe '#Objc' do
28
+ describe 'Objc' do
29
29
  it 'has generate method' do
30
30
  expect(generator).to respond_to(:generate)
31
31
  end
@@ -37,7 +37,7 @@ describe IOSGen::Generator::BaseGenerator do
37
37
  file_path = File.dirname(__FILE__) + '/spec.json'
38
38
  generator = described_class.new(type: :objc,
39
39
  file_spec: file_path)
40
- puts file_path
40
+
41
41
  before(:all) do
42
42
  generator.generate
43
43
  end
@@ -78,6 +78,41 @@ describe IOSGen::Generator::BaseGenerator do
78
78
  expect(File).to exist(file_path_protocol)
79
79
  end
80
80
  end
81
+
82
+
83
+ describe '#generate_test' do
84
+ it 'has a generate_test method' do
85
+ expect(generator).to respond_to(:generate_test)
86
+ end
87
+
88
+ context 'No spec file' do
89
+ end
90
+
91
+ context 'New Test files' do
92
+ file_path = File.dirname(__FILE__) + '/spec.json'
93
+ generator = described_class.new(type: :objc,
94
+ file_spec: file_path)
95
+
96
+ before(:all) do
97
+ generator.generate_test
98
+ end
99
+
100
+ after(:all) do
101
+ FileUtils.rm(File.expand_path('../../../FJBNotificationsViewModelTests.m', File.dirname(__FILE__)))
102
+ FileUtils.rm(File.expand_path('../../../FJBNotificationsApiInteractorTests.m', File.dirname(__FILE__)))
103
+ end
104
+
105
+ it 'has to generate ViewModels unit test files' do
106
+ file_path_test = File.expand_path('../../../FJBNotificationsViewModelTests.m', File.dirname(__FILE__))
107
+ expect(File).to exist(file_path_test)
108
+ end
109
+
110
+ it 'has to generate Interactors unit test files' do
111
+ file_path_test = File.expand_path('../../../FJBNotificationsApiInteractorTests.m', File.dirname(__FILE__))
112
+ expect(File).to exist(file_path_test)
113
+ end
114
+ end
115
+ end
81
116
  end
82
117
 
83
118
  end
@@ -26,6 +26,11 @@ describe IOSGen::Generator::Objc::ActionFormatter do
26
26
  expect(result).to eq(expected_string)
27
27
  end
28
28
 
29
+ it 'has to generate test format' do
30
+ expected_string = "// Dismiss the ViewController when the button is tapped\n\n- (void)testdidTapOnCloseButtonShouldPass\n{\n // given\n // when\n // then\n XCTFail(@\"No implemented test\");\n}\n"
31
+ result = action_generator.generate_test(action)
32
+ expect(result).to eq(expected_string)
33
+ end
29
34
  end
30
35
 
31
36
  describe 'Actions with an argument' do
@@ -50,6 +55,11 @@ describe IOSGen::Generator::Objc::ActionFormatter do
50
55
  expect(result).to eq(expected_string)
51
56
  end
52
57
 
58
+ it 'has to generate test format' do
59
+ expected_string = "// Dismiss the ViewController when the button is tapped\n\n- (void)testdidTapOnCloseButtonShouldPass\n{\n // given\n // when\n // then\n XCTFail(@\"No implemented test\");\n}\n"
60
+ result = action_generator.generate_test(action)
61
+ expect(result).to eq(expected_string)
62
+ end
53
63
  end
54
64
 
55
65
  describe 'Actions with multiples arguments' do
@@ -83,6 +93,11 @@ describe IOSGen::Generator::Objc::ActionFormatter do
83
93
  result = action_generator.generate_implementation(action)
84
94
  expect(result).to eq(expected_string)
85
95
  end
86
- end
87
96
 
97
+ it 'has to generate test format' do
98
+ expected_string = "// Dismiss the ViewController when the button is tapped\n\n- (void)testdidTapOnCloseButtonsuccessShouldPass\n{\n // given\n // when\n // then\n XCTFail(@\"No implemented test\");\n}\n"
99
+ result = action_generator.generate_test(action)
100
+ expect(result).to eq(expected_string)
101
+ end
102
+ end
88
103
  end
@@ -48,7 +48,7 @@ describe IOSGen::Generator::Objc::InteractorFormatter do
48
48
  end
49
49
  end
50
50
 
51
- describe 'Generate' do
51
+ describe '#generate' do
52
52
  it 'has to yield 3 times' do
53
53
  expect { |b| formatter.generate(&b) }.to yield_control.exactly(3).times
54
54
  end
@@ -48,5 +48,4 @@ describe IOSGen::Generator::Objc::Formatter do
48
48
  expect { |b| formatter.generate(&b) }.to yield_control.exactly(8).times
49
49
  end
50
50
  end
51
-
52
51
  end
@@ -120,6 +120,5 @@ describe IOSGen::Generator::Objc::ViewModelFormatter do
120
120
  expect(file_names[5]).to eq(formatter.interactor_formatter.impl_file_name)
121
121
  expect(templates[5]).to eq('templates/objc/Interactor.m.erb')
122
122
  end
123
-
124
123
  end
125
124
  end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe IOSGen::Generator::Objc::XctestcaseFormatter do
4
+ context 'Formatter with all object properties' do
5
+ description = 'State of NotificationViewController and perform bussiness logic'
6
+
7
+ name = 'FJBNotificationsViewModel'
8
+
9
+ properties = [Property.new(type: 'NSIndexPath *', name: 'selectedIndexPath')]
10
+
11
+ actions = [Action.new(description: 'Dismiss the ViewController when the button is tapped',
12
+ return_type: 'void',
13
+ name: 'didTapOnCloseButton'),
14
+ Action.new(description: 'Mark notification as read when the notification is selected',
15
+ return_type: 'void',
16
+ name: 'didTapAtIndexPath:',
17
+ arguments: [Property.new(type: 'NSIndexPath *',
18
+ name: 'indexPath')])]
19
+
20
+ view_model = ViewModel.new(description: description,
21
+ name: name,
22
+ properties: properties,
23
+ actions: actions)
24
+
25
+ formatter = described_class.new
26
+ formatter.object = view_model
27
+
28
+ describe '#Properties' do
29
+ it 'has a name' do
30
+ expect(formatter.name).to eq('FJBNotificationsViewModelTests')
31
+ end
32
+
33
+ it 'has file_name' do
34
+ expect(formatter.file_name).to eq('FJBNotificationsViewModelTests.m')
35
+ end
36
+
37
+ it 'has class_test_name' do
38
+ expect(formatter.class_test_name).to eq('FJBNotificationsViewModel.h')
39
+ end
40
+
41
+ it 'has actions_impl' do
42
+ expected_string = "// Dismiss the ViewController when the button is tapped\n\n- (void)testdidTapOnCloseButtonShouldPass\n{\n // given\n // when\n // then\n XCTFail(@\"No implemented test\");\n}\n\n// Mark notification as read when the notification is selected\n\n- (void)testdidTapAtIndexPathShouldPass\n{\n // given\n // when\n // then\n XCTFail(@\"No implemented test\");\n}\n"
43
+ expect(formatter.actions_impl).to eq(expected_string)
44
+ end
45
+ end
46
+
47
+ describe '#generate' do
48
+ it 'has to yield 2 times' do
49
+ expect { |b| formatter.generate(&b) }.to yield_control.exactly(1).times
50
+ end
51
+
52
+ file_names = []
53
+ templates = []
54
+
55
+ formatter.generate do |file_name, template|
56
+ file_names << file_name
57
+ templates << template
58
+ end
59
+
60
+ it 'has to return ViewModel test file name and template' do
61
+ expect(file_names[0]).to eq(formatter.file_name)
62
+ expect(templates[0]).to eq('templates/objc/XCTestCase.m.erb')
63
+ end
64
+ end
65
+ end
66
+
67
+ context 'Formatter with no properties' do
68
+ view_model = 'ViewModel.new'
69
+
70
+ formatter = described_class.new
71
+ formatter.object = view_model
72
+
73
+ describe '#Properties' do
74
+ it 'has a name' do
75
+ expect(formatter.name).to be_nil
76
+ end
77
+
78
+ it 'has file_name' do
79
+ expect(formatter.file_name).to be_nil
80
+ end
81
+
82
+ it 'has class_test_name' do
83
+ expect(formatter.class_test_name).to be_nil
84
+ end
85
+
86
+ it 'has actions_impl' do
87
+ expect(formatter.actions_impl).to be_nil
88
+ end
89
+ end
90
+ end
91
+ end
@@ -1,6 +1,6 @@
1
1
  #import "<%=@formatter.view_model_formatter.interactor_formatter.protocol_file_name%>"
2
2
 
3
- @interface <%=@formatter.view_model_formatter.interactor_formatter.interactor.name%> <<%=@formatter.view_model_formatter.interactor_formatter.protocol_name%>>
3
+ @interface <%=@formatter.view_model_formatter.interactor_formatter.interactor.name%> : NSObject <<%=@formatter.view_model_formatter.interactor_formatter.protocol_name%>>
4
4
  <%if @formatter.view_model_formatter.interactor_formatter.properties_header.nil?%>
5
5
  // -- Properties
6
6
  <%=@formatter.view_model_formatter.interactor_formatter.properties_header %>
@@ -1,3 +1,5 @@
1
+ #import <Foundation/Foundation.h>
2
+
1
3
  @protocol <%=@formatter.view_model_formatter.interactor_formatter.protocol_name%> <NSObject>
2
4
  <%if @formatter.view_model_formatter.interactor_formatter.properties_header.nil?%>
3
5
  // -- Properties
@@ -1,6 +1,6 @@
1
1
  #import "<%=@formatter.view_model_formatter.protocol_file_name%>"
2
2
 
3
- @interface <%=@view_model.name %> <<%=@formatter.view_model_formatter.protocol_name%>>
3
+ @interface <%=@view_model.name %> : NSObject <<%=@formatter.view_model_formatter.protocol_name%>>
4
4
 
5
5
  // -- Properties
6
6
  <%=@formatter.view_model_formatter.properties_header %>