defgen 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.
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
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in defgen.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,56 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ defgen (0.0.1)
5
+ xcodeproj
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (3.2.9)
11
+ i18n (~> 0.6)
12
+ multi_json (~> 1.0)
13
+ coderay (1.0.8)
14
+ colored (1.2)
15
+ diff-lcs (1.1.3)
16
+ guard (1.6.0)
17
+ listen (>= 0.6.0)
18
+ lumberjack (>= 1.0.2)
19
+ pry (>= 0.9.10)
20
+ thor (>= 0.14.6)
21
+ guard-rspec (2.3.3)
22
+ guard (>= 1.1)
23
+ rspec (~> 2.11)
24
+ i18n (0.6.1)
25
+ listen (0.6.0)
26
+ lumberjack (1.0.2)
27
+ method_source (0.8.1)
28
+ multi_json (1.5.0)
29
+ pry (0.9.10)
30
+ coderay (~> 1.0.5)
31
+ method_source (~> 0.8)
32
+ slop (~> 3.3.1)
33
+ rb-fsevent (0.9.2)
34
+ rspec (2.12.0)
35
+ rspec-core (~> 2.12.0)
36
+ rspec-expectations (~> 2.12.0)
37
+ rspec-mocks (~> 2.12.0)
38
+ rspec-core (2.12.2)
39
+ rspec-expectations (2.12.1)
40
+ diff-lcs (~> 1.1.3)
41
+ rspec-mocks (2.12.1)
42
+ slop (3.3.3)
43
+ thor (0.16.0)
44
+ xcodeproj (0.4.0)
45
+ activesupport (~> 3.2.6)
46
+ colored (~> 1.2)
47
+
48
+ PLATFORMS
49
+ ruby
50
+
51
+ DEPENDENCIES
52
+ defgen!
53
+ guard
54
+ guard-rspec
55
+ rb-fsevent
56
+ rspec
data/Guardfile ADDED
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012-2013 Paul Samuels
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,151 @@
1
+ ##NSUserDefaults using properties
2
+
3
+ Using properties to access data from `NSUserDefaults` is a million times better than using the verbose API. To do this you simply make a category on `NSUserDefaults` and then chuck in some boiler plate code to hook it all up.
4
+
5
+ It couldn't be simpler...
6
+
7
+ ##Defgen makes it simpler
8
+
9
+ Boiler plate is boring so why write it? Using Defgen we can have the computer write it for us. Supply a `Defaultfile` written in the super simple DSL and `defgen` will do the rest.
10
+
11
+ ##Features
12
+
13
+ This is firmly in the realms of Proof of Concept at the minute but.
14
+
15
+ - Uses class prefix used in your Xcodeproj
16
+ - Uses the OrganizationName in your Xcodeproj
17
+ - Customizable boiler plate
18
+ - No runtime tricks and all the `NSUserDefault` supported types are supported
19
+ - Automatically updates your Xcodeproj
20
+
21
+ ##Usage
22
+
23
+ ####Step 1. Supply a Defaultfile
24
+
25
+ # ├── AwesomeApp/
26
+ # ├── AwesomeApp/
27
+ # ├── AwesomeApp.xcodeproj/
28
+ # ├── Defaultfile <----- Your Defaultfile
29
+
30
+ # Defaultfile
31
+ array 'cheatCodes'
32
+ bool 'firstUse'
33
+ data 'someData'
34
+ dictionary 'config'
35
+ float 'ratio'
36
+ integer 'year'
37
+ object 'mmmmmm'
38
+ string 'name'
39
+ double 'betterRatio'
40
+ url 'homepage'
41
+
42
+ The DSL should be pretty self explanatory call the `type` of the object followed by what you want to call it.
43
+
44
+ ####Step 2. Run Defgen
45
+
46
+ $ defgen
47
+
48
+ ####Step 3. Enjoy the generated boiler plate
49
+
50
+ ###Customisation
51
+
52
+ If you don't like the supplied boiler plate then you can tweak it.
53
+
54
+ ####Step 1. Call generate the stubs
55
+
56
+ $ defgen stubs
57
+
58
+ This will generate the templates in your current project so that you can edit as much as you like
59
+
60
+ create defgen/constant.erb
61
+ create defgen/getter.erb
62
+ create defgen/implementation.erb
63
+ create defgen/interface.erb
64
+ create defgen/property.erb
65
+ create defgen/setter.erb
66
+
67
+ ##Example input/output/usage
68
+
69
+ ####Input
70
+
71
+ #Defaultfile
72
+
73
+ array 'aliases'
74
+
75
+ ####Output
76
+
77
+ //
78
+ // NSUserDefaults+PASProperties.h
79
+ // AwesomeApp
80
+ //
81
+ // Created by Paul Samuels on 04/01/2013.
82
+ // Copyright (c) 2013 Paul Samuels. All rights reserved.
83
+ //
84
+ // This is an autogenerated file any changes will be lost when running `defgen`
85
+ //
86
+
87
+ #import <Foundation/Foundation.h>
88
+
89
+ @interface NSUserDefaults (PASProperties)
90
+
91
+ @property (nonatomic, strong) NSArray *pas_aliases;
92
+
93
+ @end
94
+
95
+ //
96
+ // NSUserDefaults+PASProperties.m
97
+ // AwesomeApp
98
+ //
99
+ // Created by Paul Samuels on 04/01/2013.
100
+ // Copyright (c) 2013 Paul Samuels. All rights reserved.
101
+ //
102
+ // This is an autogenerated file any changes will be lost when running `defgen`
103
+ //
104
+
105
+ #import "NSUserDefaults+PASProperties.h"
106
+
107
+ NSString * const PASAliases = @"PASAliases";
108
+
109
+ @implementation NSUserDefaults (PASProperties)
110
+
111
+ - (NSArray *)pas_aliases;
112
+ {
113
+ return [self arrayForKey:PASAliases];
114
+ }
115
+
116
+ - (void)setPas_aliases:(NSArray *)aliases;
117
+ {
118
+ [self setObject:aliases forKey:PASAliases];
119
+ }
120
+
121
+ @end
122
+
123
+ ####Usage
124
+
125
+ #import "NSUserDefaults+PASProperties.h"
126
+
127
+ ...
128
+
129
+ userDefaults.pas_aliases = @[ @1, @2 ];
130
+ NSLog(@"%@", userDefaults.pas_aliases);
131
+
132
+ ## Installation
133
+
134
+ $ gem install defgen
135
+
136
+ ## Contributing
137
+
138
+ 1. Fork it
139
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
140
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
141
+ 4. Push to the branch (`git push origin my-new-feature`)
142
+ 5. Create new Pull Request
143
+
144
+ ##Wish List
145
+
146
+ - Support for provising customer getter e.g. `(nonatomic, strong, getter=isValid)`
147
+ - Support for overriding ownership qualifiers
148
+
149
+ ##Licence
150
+
151
+ Defgen is available under the MIT license. See the LICENSE file for more info.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/defgen ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'defgen'
4
+
5
+ Defgen::CLI.start
data/defgen.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'defgen/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "defgen"
8
+ gem.version = Defgen::VERSION
9
+ gem.authors = ["Paul Samuels"]
10
+ gem.email = ["paulio1987@gmail.com"]
11
+ gem.description = %q{Build an NSUserDefaults category using a simple DSL}
12
+ gem.summary = %q{Build an NSUserDefaults category using a simple DSL}
13
+ gem.homepage = "https://github.com/paulsamuels/Defgen"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ gem.add_dependency 'xcodeproj'
20
+ gem.add_development_dependency "rspec"
21
+ gem.add_development_dependency "guard"
22
+ gem.add_development_dependency "guard-rspec"
23
+ gem.add_development_dependency "rb-fsevent"
24
+ end
Binary file
data/lib/defgen/cli.rb ADDED
@@ -0,0 +1,47 @@
1
+ require 'Thor'
2
+ require 'fileutils'
3
+
4
+ module Defgen
5
+ class CLI < Thor
6
+
7
+ desc "stubs", "Generate template stubs"
8
+ def stubs
9
+ TemplateGenerator.create_stubs
10
+ end
11
+
12
+ desc "parse", 'Parse a "Defaultfile" and modify the Xcodeproj'
13
+ method_option :filename, default: 'Defaultfile',
14
+ aliases: '-f',
15
+ desc: 'Specify the input file path'
16
+ def parse
17
+
18
+ path = Dir['*.xcodeproj'].first
19
+
20
+ if path.nil?
21
+ puts('.xcodeproj file not found')
22
+ puts
23
+ help
24
+ exit 1
25
+ end
26
+
27
+ unless File.exist? options[:filename]
28
+ puts('no Defaultfile found')
29
+ puts
30
+ help
31
+ exit 1
32
+ end
33
+
34
+ proj = XcodeprojAdapter.new(Xcodeproj::Project.new(path), path)
35
+
36
+ defaultfile = DefaultfileBuilder.build { |builder|
37
+ builder.project_settings = proj
38
+ builder.parser = DefaultfileParser
39
+ builder.defaultfile = File.open(options[:filename]).read
40
+ }
41
+
42
+ Installer.install(path, defaultfile, proj)
43
+ end
44
+
45
+ default_task :parse
46
+ end
47
+ end
@@ -0,0 +1,17 @@
1
+ require 'delegate'
2
+
3
+ module Defgen
4
+ class GetterDecorator < SimpleDelegator
5
+ def objc_type
6
+ super.strip
7
+ end
8
+
9
+ def prefix
10
+ super.downcase
11
+ end
12
+
13
+ def get_binding
14
+ binding
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module Defgen
2
+ class SetterDecorator < GetterDecorator
3
+ def message_prefix
4
+ object_setter ? 'Object' : super.upcase_first
5
+ end
6
+
7
+ def prefix
8
+ super.downcase.upcase_first
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,2 @@
1
+ require 'defgen/decorators/getter_decorator'
2
+ require 'defgen/decorators/setter_decorator'
@@ -0,0 +1,65 @@
1
+ require 'date'
2
+
3
+ module Defgen
4
+ class Defaultfile
5
+ attr_accessor :project_settings
6
+ attr_reader :class_properties
7
+
8
+ def initialize class_properties, project_settings
9
+ @class_properties = class_properties
10
+ self.project_settings = project_settings
11
+ end
12
+
13
+ def to_iface
14
+ render TemplateGenerator.interface_template
15
+ end
16
+
17
+ def to_imp
18
+ render TemplateGenerator.implementation_template
19
+ end
20
+
21
+ private
22
+
23
+ def render template
24
+ prefix = project_settings.prefix
25
+ project_name = project_settings.name
26
+ author = project_settings.organization
27
+
28
+ ERB.new(template, nil, '<>').result binding
29
+ end
30
+
31
+ def key_constants
32
+ padding = class_properties.max_by { |p| p.key.length }.key.length
33
+ constant_template = TemplateGenerator.constant_template
34
+
35
+ String.new.tap { |out|
36
+ class_properties.each do |property|
37
+ out << ERB.new(constant_template).result(binding)
38
+ end
39
+ }
40
+ end
41
+
42
+ def accessors
43
+ getter_template = TemplateGenerator.getter_template
44
+ setter_template = TemplateGenerator.setter_template
45
+
46
+ String.new.tap { |out|
47
+ class_properties.each do |property|
48
+ out << ERB.new(getter_template).result(GetterDecorator.new(property).get_binding) + "\n"
49
+ out << ERB.new(setter_template).result(SetterDecorator.new(property).get_binding)
50
+ out << "\n" unless class_properties.last == property
51
+ end
52
+ }
53
+ end
54
+
55
+ def properties
56
+ property_template = TemplateGenerator.property_template
57
+
58
+ String.new.tap { |out|
59
+ class_properties.each do |property|
60
+ out << ERB.new(property_template).result(property.get_binding)
61
+ end
62
+ }
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,14 @@
1
+ module Defgen
2
+ class DefaultfileBuilder
3
+ attr_accessor :parser, :project_settings, :defaultfile
4
+
5
+ def self.build
6
+ new.tap { |instance| yield(instance) }.build
7
+ end
8
+
9
+ def build
10
+ properties = parser.parse(defaultfile).each do |property| property.prefix = project_settings.prefix end
11
+ Defaultfile.new properties, project_settings
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,41 @@
1
+ module Defgen
2
+ class DefaultfileParser
3
+ def self.parse string
4
+ new.parse string
5
+ end
6
+
7
+ def initialize
8
+ @properties = []
9
+ end
10
+
11
+ [
12
+ [ 'array', 'array', 'NSArray *', :strong, true ],
13
+ [ 'bool', 'bool', 'BOOL ', :assign, false ],
14
+ [ 'data', 'data', 'NSData *', :strong, true ],
15
+ [ 'dictionary', 'dictionary', 'NSDictionary *', :strong, true ],
16
+ [ 'float', 'float', 'float ', :assign, false ],
17
+ [ 'integer', 'integer', 'NSInteger ', :assign, false ],
18
+ [ 'object', 'object', 'id ', :strong, true ],
19
+ [ 'string', 'string', 'NSString *', :copy, true ],
20
+ [ 'double', 'double', 'double ', :assign, false ],
21
+ [ 'url', 'URL', 'NSURL *', :strong, false ]
22
+ ].each do |method_name, prefix, objc_type, ownership, object_setter|
23
+ define_method method_name do |name|
24
+ Property.new do |property, attributes|
25
+ property.name = name
26
+ property.object_setter = object_setter
27
+ property.message_prefix = prefix
28
+ property.objc_type = objc_type
29
+ attributes.ownership = ownership
30
+
31
+ @properties << property
32
+ end
33
+ end
34
+ end
35
+
36
+ def parse string
37
+ instance_eval string
38
+ @properties
39
+ end
40
+ end
41
+ end
Binary file
@@ -0,0 +1,38 @@
1
+ require 'thor/group'
2
+
3
+ class TemplateGenerator < Thor::Group
4
+ include Thor::Actions
5
+
6
+ def self.source_root
7
+ File.join(File.dirname(__FILE__), 'templates')
8
+ end
9
+
10
+ templates = Dir.glob("#{source_root}/*.erb")
11
+ TEMPLATES = templates.map { |f| File.basename(f, '.erb') }
12
+
13
+ TEMPLATES.each do |template|
14
+ const_set "#{template.upcase}_SOURCE", File.join(source_root, "#{template}.erb")
15
+ const_set "#{template.upcase}_DEST", "defgen/#{template}.erb"
16
+
17
+ self.class.send :define_method, "#{template}_template" do
18
+ load_template const_get("#{template.upcase}_SOURCE"), const_get("#{template.upcase}_DEST")
19
+ end
20
+ end
21
+
22
+ def self.create_stubs
23
+ new.create_stubs
24
+ end
25
+
26
+ def create_stubs
27
+ TEMPLATES.map(&:upcase).each do |template_file|
28
+ template self.class.const_get("#{template_file}_SOURCE"), self.class.const_get("#{template_file}_DEST")
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def self.load_template source, destination
35
+ return File.open(destination).read if File.exist? destination
36
+ ERB.new(File.open(source).read).result
37
+ end
38
+ end
@@ -0,0 +1 @@
1
+ NSString * const <%%= property.key.ljust(padding) %> = @"<%%= property.key %>";
@@ -0,0 +1,4 @@
1
+ - (<%%= objc_type %>)<%%= prefix %>_<%%= parameter %>;
2
+ {
3
+ return [self <%%= message_prefix %>ForKey:<%%= key %>];
4
+ }
@@ -0,0 +1,19 @@
1
+ //
2
+ // NSUserDefaults+<%%= prefix %>Properties.m
3
+ // <%%= project_name %>
4
+ //
5
+ // Created by <%%= author %> on <%= Date.today.strftime('%d/%m/%Y') %>.
6
+ // Copyright (c) <%= Date.today.year %> <%%= author %>. All rights reserved.
7
+ //
8
+ // This is an autogenerated file any changes will be lost when running `defgen`
9
+ //
10
+
11
+ #import "NSUserDefaults+<%%= prefix %>Properties.h"
12
+
13
+ <%%= key_constants %>
14
+
15
+ @implementation NSUserDefaults (<%%= prefix %>Properties)
16
+
17
+ <%%= accessors %>
18
+
19
+ @end
@@ -0,0 +1,17 @@
1
+ //
2
+ // NSUserDefaults+<%%= prefix %>Properties.h
3
+ // <%%= project_name %>
4
+ //
5
+ // Created by <%%= author %> on <%= Date.today.strftime('%d/%m/%Y') %>.
6
+ // Copyright (c) <%= Date.today.year %> <%%= author %>. All rights reserved.
7
+ //
8
+ // This is an autogenerated file any changes will be lost when running `defgen`
9
+ //
10
+
11
+ #import <Foundation/Foundation.h>
12
+
13
+ @interface NSUserDefaults (<%%= prefix %>Properties)
14
+
15
+ <%%= properties %>
16
+
17
+ @end
@@ -0,0 +1 @@
1
+ @property <%%= attributes %> <%%= objc_type %><%%= prefix.downcase %>_<%%= name %>;
@@ -0,0 +1,4 @@
1
+ - (void)set<%%= prefix %>_<%%= name %>:(<%%= objc_type %>)<%%= parameter %>;
2
+ {
3
+ [self set<%%= message_prefix %>:<%%= parameter %> forKey:<%%= key %>];
4
+ }
@@ -0,0 +1 @@
1
+ require 'defgen/generators/template/template_generator'
@@ -0,0 +1 @@
1
+ require 'defgen/generators/template'