defgen 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +56 -0
  4. data/Guardfile +9 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +151 -0
  7. data/Rakefile +1 -0
  8. data/bin/defgen +5 -0
  9. data/defgen.gemspec +24 -0
  10. data/lib/defgen/.DS_Store +0 -0
  11. data/lib/defgen/cli.rb +47 -0
  12. data/lib/defgen/decorators/getter_decorator.rb +17 -0
  13. data/lib/defgen/decorators/setter_decorator.rb +11 -0
  14. data/lib/defgen/decorators.rb +2 -0
  15. data/lib/defgen/defaultfile.rb +65 -0
  16. data/lib/defgen/defaultfile_builder.rb +14 -0
  17. data/lib/defgen/defaultfile_parser.rb +41 -0
  18. data/lib/defgen/generators/.DS_Store +0 -0
  19. data/lib/defgen/generators/template/template_generator.rb +38 -0
  20. data/lib/defgen/generators/template/templates/constant.erb +1 -0
  21. data/lib/defgen/generators/template/templates/getter.erb +4 -0
  22. data/lib/defgen/generators/template/templates/implementation.erb +19 -0
  23. data/lib/defgen/generators/template/templates/interface.erb +17 -0
  24. data/lib/defgen/generators/template/templates/property.erb +1 -0
  25. data/lib/defgen/generators/template/templates/setter.erb +4 -0
  26. data/lib/defgen/generators/template.rb +1 -0
  27. data/lib/defgen/generators.rb +1 -0
  28. data/lib/defgen/installer.rb +75 -0
  29. data/lib/defgen/property/attributes.rb +29 -0
  30. data/lib/defgen/property.rb +30 -0
  31. data/lib/defgen/string_ext.rb +5 -0
  32. data/lib/defgen/version.rb +3 -0
  33. data/lib/defgen/xcodeproj_adapter.rb +48 -0
  34. data/lib/defgen.rb +14 -0
  35. data/spec/integration/defaultfile_parse_spec.rb +28 -0
  36. data/spec/support/property_accessor_examples.rb +12 -0
  37. data/spec/support/property_examples.rb +58 -0
  38. data/spec/support/spec_helper.rb +2 -0
  39. data/spec/unit/decorators/getter_decorator_spec.rb +31 -0
  40. data/spec/unit/decorators/setter_decorator_spec.rb +42 -0
  41. data/spec/unit/defaultfile_builder_spec.rb +12 -0
  42. data/spec/unit/defaultfile_parser_spec.rb +42 -0
  43. data/spec/unit/defautfile_spec.rb +11 -0
  44. data/spec/unit/property/attributes_spec.rb +48 -0
  45. data/spec/unit/property/property_spec.rb +10 -0
  46. data/spec/unit/string_ext_spec.rb +17 -0
  47. data/spec/unit/xcodeproj_adapter_spec.rb +10 -0
  48. metadata +186 -0
@@ -0,0 +1,75 @@
1
+ module Defgen
2
+ class Installer
3
+ def self.install(path, defaultfile, proj)
4
+ new(path, defaultfile, proj).install
5
+ end
6
+
7
+ def initialize path, defaultfile, proj
8
+ self.path, self.defaultfile, self.proj = path, defaultfile, proj
9
+ end
10
+
11
+ def install
12
+ install_files
13
+ configure_xcode
14
+ proj.save
15
+ end
16
+
17
+ private
18
+
19
+ attr_accessor :path, :defaultfile, :proj
20
+
21
+ def install_files
22
+ FileUtils.mkdir_p properties_path
23
+
24
+ { '.h' => defaultfile.to_iface, '.m' => defaultfile.to_imp }.each do |ext, content|
25
+ File.open("#{file_path}#{ext}", 'w') do |f|
26
+ f.puts content
27
+ end
28
+ end
29
+ end
30
+
31
+ def configure_xcode
32
+ return if proj.objects.map { |o| o.name if o.respond_to? :name }.include? "#{file_name}.h"
33
+
34
+ main_group.new_file "#{file_path}.h", properties_group
35
+ implementation = main_group.new_file "#{file_path}.m", properties_group
36
+ main_target.source_build_phase.add_file_reference implementation
37
+ end
38
+
39
+ def properties_path
40
+ "#{File.dirname(path)}/#{target_name}/#{prefix}Properties"
41
+ end
42
+
43
+ def properties_group
44
+ "#{prefix}Properties"
45
+ end
46
+
47
+ def properties_group_path
48
+ "#{main_target_name}/#{properties_group}"
49
+ end
50
+
51
+ def file_path
52
+ "#{properties_path}/#{file_name}"
53
+ end
54
+
55
+ def file_name
56
+ "NSUserDefaults+#{prefix}Properties"
57
+ end
58
+
59
+ def prefix
60
+ proj.prefix.upcase
61
+ end
62
+
63
+ def main_group
64
+ proj.main_group
65
+ end
66
+
67
+ def main_target
68
+ proj.main_target
69
+ end
70
+
71
+ def target_name
72
+ main_target.name
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,29 @@
1
+ module Defgen
2
+ class Property
3
+ class UnsupportedOwnershipError < ArgumentError; end
4
+ class Attributes
5
+ VALID_OWNERSHIPS = [:strong, :weak, :assign, :unsafe_unretained, :retain, :copy]
6
+ attr_accessor :ownership
7
+
8
+ def initialize
9
+ @ownership = :strong
10
+ end
11
+
12
+ def ownership= ownership
13
+ raise UnsupportedOwnershipError unless ownership.nil? || VALID_OWNERSHIPS.include?(ownership)
14
+ @ownership = ownership
15
+ end
16
+
17
+ VALID_OWNERSHIPS.each do |ownership|
18
+ # Turn valid ownerships into predicate methods. e.g. strong?
19
+ define_method "#{ownership}?" do
20
+ instance_variable_get("@ownership") == ownership
21
+ end
22
+ end
23
+
24
+ def to_s
25
+ "(#{['nonatomic', ownership].compact.join(', ')})"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ module Defgen
2
+ class Property
3
+ VALID_TYPES = ['NSData *', 'NSArray *', 'BOOL ', 'NSDictionary *', 'float ', 'NSInteger ', 'id ', 'NSString *', 'double ', 'NSURL *']
4
+ attr_accessor :name, :objc_type, :message_prefix, :prefix, :attributes, :object_setter
5
+
6
+ def initialize
7
+ self.attributes = Attributes.new
8
+ yield self, attributes if block_given?
9
+ end
10
+
11
+ def objc_type= objc_type
12
+ raise ArgumentError unless VALID_TYPES.include? objc_type
13
+ @objc_type = objc_type
14
+ end
15
+
16
+ def key
17
+ "#{prefix.upcase}#{name.upcase_first}"
18
+ end
19
+
20
+ def parameter
21
+ name
22
+ end
23
+
24
+ def get_binding
25
+ binding
26
+ end
27
+ end
28
+ end
29
+
30
+ require 'defgen/property/attributes'
@@ -0,0 +1,5 @@
1
+ class String
2
+ def upcase_first
3
+ self.dup.tap { |string| string[0] = string[0].upcase }
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Defgen
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,48 @@
1
+ require 'xcodeproj'
2
+
3
+ module Defgen
4
+ class XcodeprojAdapter
5
+ def initialize proj, path
6
+ @proj, @path = proj, path
7
+ end
8
+
9
+ def name
10
+ @proj.targets.first.name
11
+ end
12
+
13
+ def prefix
14
+ prefix = root_object.attributes['CLASSPREFIX']
15
+ if prefix.nil? || prefix.empty?
16
+ 'PS'
17
+ else
18
+ prefix.upcase
19
+ end
20
+ end
21
+
22
+ def objects
23
+ @proj.objects
24
+ end
25
+
26
+ def organization
27
+ root_object.attributes['ORGANIZATIONNAME']
28
+ end
29
+
30
+ def main_group
31
+ root_object.main_group.groups.first
32
+ end
33
+
34
+ def main_target
35
+ root_object.targets.first
36
+ end
37
+
38
+ def save
39
+ @proj.save_as @path
40
+ end
41
+
42
+ private
43
+
44
+ def root_object
45
+ @proj.root_object
46
+ end
47
+ end
48
+ end
data/lib/defgen.rb ADDED
@@ -0,0 +1,14 @@
1
+ module Defgen
2
+ end
3
+
4
+ require 'defgen/string_ext'
5
+ require 'defgen/cli'
6
+ require 'defgen/decorators'
7
+ require 'defgen/defaultfile'
8
+ require 'defgen/defaultfile_builder'
9
+ require 'defgen/defaultfile_parser'
10
+ require 'defgen/installer'
11
+ require 'defgen/generators'
12
+ require 'defgen/property'
13
+ require 'defgen/version'
14
+ require 'defgen/xcodeproj_adapter'
@@ -0,0 +1,28 @@
1
+ require 'support/spec_helper'
2
+ require 'defgen/defaultfile'
3
+
4
+ module Defgen
5
+ describe 'Defaultfile.parse' do
6
+
7
+ # [
8
+ # { prefix: 'bool', name: 'valid', objc_type: 'BOOL', ownership: :assign },
9
+ # { prefix: 'array', name: 'collection', objc_type: 'NSArray *', ownership: :strong },
10
+ # { prefix: 'data', name: 'someData', objc_type: 'NSData *', ownership: :strong },
11
+ # { prefix: 'dictionary', name: 'options', objc_type: 'NSDictionary *', ownership: :strong },
12
+ # { prefix: 'float', name: 'ratio', objc_type: 'float', ownership: :assign },
13
+ # { prefix: 'integer', name: 'count', objc_type: 'NSInteger', ownership: :assign },
14
+ # { prefix: 'object', name: 'someObject', objc_type: 'id', ownership: :strong },
15
+ # { prefix: 'string', name: 'user_name', objc_type: 'NSString *', ownership: :copy },
16
+ # { prefix: 'double', name: 'ratio', objc_type: 'double', ownership: :assign },
17
+ # { prefix: 'url', name: 'someWebsite', objc_type: 'NSURL *', ownership: :strong },
18
+ # ].each do |options|
19
+ # it "creates a valid #{options[:prefix]}" do
20
+ # result = Defaultfile.parse "#{options[:prefix]} '#{options[:name]}'"
21
+ # result.name.should eq(options[:name])
22
+ # result.message_prefix.should eq(options[:prefix])
23
+ # result.objc_type.should eq(options[:objc_type])
24
+ # result.attributes.ownership.should eq(options[:ownership])
25
+ # end
26
+ # end
27
+ end
28
+ end
@@ -0,0 +1,12 @@
1
+ require 'support/spec_helper'
2
+
3
+ module Defgen
4
+ shared_examples "property accessors" do
5
+ it { should respond_to :name }
6
+ it { should respond_to :objc_type }
7
+ it { should respond_to :message_prefix }
8
+ it { should respond_to :attributes }
9
+ it { should respond_to :object_setter }
10
+ it { should respond_to :parameter }
11
+ end
12
+ end
@@ -0,0 +1,58 @@
1
+ require 'support/spec_helper'
2
+ require 'defgen/property'
3
+
4
+ module Defgen
5
+ shared_examples "a property" do
6
+ let(:property) { described_class.new }
7
+
8
+ it { should respond_to :name }
9
+ it { should respond_to :objc_type }
10
+ it { should respond_to :message_prefix }
11
+ it { should respond_to :attributes }
12
+ it { should respond_to :object_setter }
13
+ it { should respond_to :parameter }
14
+
15
+ specify { expect { |b| described_class.new(&b) }.to yield_control }
16
+
17
+ it "should be able to yield on new" do
18
+ expect {
19
+ described_class.new do |property, attributes|
20
+ property.objc_type = 'NSData *'
21
+ end
22
+ }.to_not raise_error
23
+
24
+ described_class.new do |property, attributes|
25
+ property.should respond_to :name
26
+ end
27
+ end
28
+
29
+ describe "objc_type=" do
30
+ good_types = Property::VALID_TYPES
31
+ bad_types = ['Test *', 'NSURLConnection *']
32
+
33
+ good_types.each do |type|
34
+ it "should allow the objc_type #{type}" do
35
+ expect { property.objc_type = type }.to_not raise_error
36
+ end
37
+ end
38
+
39
+ bad_types.each do |type|
40
+ it "should not allow the objc_type #{type}" do
41
+ expect { property.objc_type = type }.to raise_error ArgumentError
42
+ end
43
+ end
44
+ end
45
+
46
+ [
47
+ [ 'test', 'PSTest'],
48
+ [ 'isValid', 'PSIsValid'],
49
+ [ 'under_score', 'PSUnder_score']
50
+ ].each do |name, expected|
51
+ it "returns an appropriate key for #{name}" do
52
+ property.name = name
53
+ property.prefix = 'ps'
54
+ property.key.should eq(expected)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,2 @@
1
+ require 'bundler/setup'
2
+ require 'defgen'
@@ -0,0 +1,31 @@
1
+ require 'support/spec_helper'
2
+ require 'support/property_accessor_examples'
3
+ require 'defgen/property'
4
+ require 'defgen/decorators/getter_decorator'
5
+
6
+ module Defgen
7
+ describe GetterDecorator do
8
+ include_examples "property accessors"
9
+
10
+ before do
11
+ @property = Property.new
12
+ end
13
+
14
+ subject(:decorator) { GetterDecorator.new(@property) }
15
+
16
+ [
17
+ ['NSData *', 'NSData *'],
18
+ ['BOOL ', 'BOOL']
19
+ ].each do |input, output|
20
+ it "strips white space from the objc_type" do
21
+ @property.objc_type = input
22
+ decorator.objc_type.should eq(output)
23
+ end
24
+ end
25
+
26
+ it "downcases the prefix" do
27
+ @property.prefix = 'PS'
28
+ decorator.prefix.should eq('ps')
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,42 @@
1
+ require 'support/spec_helper'
2
+ require 'support/property_accessor_examples'
3
+ require 'defgen/property'
4
+ require 'defgen/decorators/setter_decorator'
5
+
6
+ module Defgen
7
+ describe SetterDecorator do
8
+ include_examples "property accessors"
9
+
10
+ before do
11
+ @property = Property.new
12
+ end
13
+
14
+ subject(:decorator) { SetterDecorator.new(@property) }
15
+
16
+ [
17
+ ['ps', 'Ps'],
18
+ ['PS', 'Ps']
19
+ ].each do |input, expected|
20
+ it "camelizes prefix" do
21
+ @property.prefix = input
22
+ decorator.prefix.should eq(expected)
23
+ end
24
+ end
25
+
26
+ [
27
+ ['data', 'Data'],
28
+ ['bool', 'Bool']
29
+ ].each do |message_prefix, expected|
30
+ it "generates a camalized message_prefix '#{expected}" do
31
+ @property.message_prefix = message_prefix
32
+ decorator.message_prefix.should eq(expected)
33
+ end
34
+ end
35
+
36
+ it "uses an Object setter" do
37
+ @property.object_setter = true
38
+ @property.message_prefix = 'Bool'
39
+ decorator.message_prefix.should eq('Object')
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,12 @@
1
+ require 'support/spec_helper'
2
+ require 'defgen/defaultfile_builder'
3
+
4
+ module Defgen
5
+ describe DefaultfileBuilder do
6
+ subject(:builder) { DefaultfileBuilder.new }
7
+
8
+ it { should respond_to :parser }
9
+ # it { should respond_to :project_settings }
10
+ it { should respond_to :build }
11
+ end
12
+ end
@@ -0,0 +1,42 @@
1
+ require 'support/spec_helper'
2
+ require 'defgen/defaultfile_parser'
3
+ require 'defgen/defaultfile'
4
+
5
+ module Defgen
6
+ describe DefaultfileParser do
7
+ subject(:defaultfile_parser) { DefaultfileParser.new }
8
+
9
+ it { DefaultfileParser.should respond_to :parse }
10
+
11
+ %w(array bool data dictionary float integer object string double url).each do |method|
12
+ it { should respond_to method }
13
+ end
14
+
15
+ it "returns a Enumerable" do
16
+ DefaultfileParser.parse('').should be_a_kind_of Enumerable
17
+ end
18
+
19
+ [
20
+ [ 'array', 'array', 'NSArray *', :strong, true ],
21
+ [ 'bool', 'bool', 'BOOL ', :assign, false ],
22
+ [ 'data', 'data', 'NSData *', :strong, true ],
23
+ [ 'dictionary', 'dictionary', 'NSDictionary *', :strong, true ],
24
+ [ 'float', 'float', 'float ', :assign, false ],
25
+ [ 'integer', 'integer', 'NSInteger ', :assign, false ],
26
+ [ 'object', 'object', 'id ', :strong, true ],
27
+ [ 'string', 'string', 'NSString *', :copy, true ],
28
+ [ 'double', 'double', 'double ', :assign, false ],
29
+ [ 'url', 'URL', 'NSURL *', :strong, false ]
30
+ ].each do |method_name, prefix, objc_type, ownership, object_setter|
31
+ it "parses the string #{method_name} 'iVar'" do
32
+ property = defaultfile_parser.parse("#{method_name} 'iVar'").first
33
+
34
+ property.name.should eq('iVar')
35
+ property.object_setter.should eq(object_setter)
36
+ property.message_prefix.should eq(prefix)
37
+ property.objc_type.should eq(objc_type)
38
+ property.attributes.ownership.should eq(ownership)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,11 @@
1
+ require 'support/spec_helper'
2
+ require 'defgen/defaultfile'
3
+
4
+ module Defgen
5
+ describe Defaultfile do
6
+ subject(:defaultfile) { Defaultfile.new [], nil }
7
+
8
+ it { should respond_to :to_iface }
9
+ it { should respond_to :to_imp }
10
+ end
11
+ end
@@ -0,0 +1,48 @@
1
+ require 'support/spec_helper'
2
+ require 'defgen/property/attributes'
3
+
4
+ module Defgen
5
+ class Property
6
+ describe Attributes do
7
+ subject(:attributes) { Attributes.new }
8
+
9
+ it { should respond_to :ownership }
10
+
11
+ Attributes::VALID_OWNERSHIPS.each do |semantic|
12
+ it "creates the predicate method #{semantic}?" do
13
+ should respond_to "#{semantic}?"
14
+ end
15
+ end
16
+
17
+ it "uses strong as the default ownership" do
18
+ attributes.ownership.should == :strong
19
+ end
20
+
21
+ describe "ownerships=" do
22
+ specify { expect { attributes.ownership = :a }.to raise_error UnsupportedOwnershipError }
23
+
24
+ Attributes::VALID_OWNERSHIPS.each do |semantic|
25
+ it "allows an ownership type of #{semantic}" do
26
+ expect { attributes.ownership = semantic }.to_not raise_error
27
+ end
28
+ end
29
+ end
30
+
31
+ describe "to_s" do
32
+ it "should default to (nonatomic, strong)" do
33
+ attributes.to_s.should eq('(nonatomic, strong)')
34
+ end
35
+
36
+ it "should include correct ownership" do
37
+ attributes.ownership = :weak
38
+ attributes.to_s.should eq('(nonatomic, weak)')
39
+ end
40
+
41
+ it "should allow nil setter semantic" do
42
+ attributes.ownership = nil
43
+ attributes.to_s.should eq('(nonatomic)')
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,10 @@
1
+ require 'support/spec_helper'
2
+ require 'support/property_examples'
3
+ require 'defgen/property'
4
+
5
+ module Defgen
6
+ describe Property do
7
+ it_behaves_like "a property"
8
+ subject(:property) { Property.new }
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ require 'support/spec_helper'
2
+ require 'defgen/string_ext'
3
+
4
+ module Defgen
5
+ describe String do
6
+ [
7
+ [ 'HEY', 'HEY' ],
8
+ [ 'Hey', 'Hey' ],
9
+ [ 'hey', 'Hey' ],
10
+ [ 'hEy', 'HEy' ]
11
+ ].each do |input, expected|
12
+ it "upcases the first letter of #{input}" do
13
+ input.upcase_first.should eq(expected)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ require 'support/spec_helper'
2
+ require 'defgen/xcodeproj_adapter'
3
+
4
+ module Defgen
5
+ describe XcodeprojAdapter do
6
+ it "takes a name, or" do
7
+
8
+ end
9
+ end
10
+ end