nidyx 0.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.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Chris Knadler
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,146 @@
1
+ # Nidyx ![Build Status](https://travis-ci.org/cknadler/nidyx.svg?branch=master)
2
+
3
+ [JSON Schema][JSONSchema] ⇒ Model.
4
+
5
+ Nidyx generates Objective-C models from JSON Schema. It can also generate
6
+ models with [JSONModel](https://github.com/icanzilb/JSONModel) support.
7
+
8
+ ## Usage
9
+
10
+ ```
11
+ usage: nidyx [-h] [--version]
12
+ nidyx <schema> <class-prefix> [output-directory]
13
+ [-j] [-n] [-a author] [-c company] [-p project]
14
+
15
+ -a, --author AUTHOR Author's name
16
+ -c, --company COMPANY Company's name
17
+ -p, --project PROJECT Project's name
18
+ -j, --json-model Generate with JSONModel support
19
+ -n, --no-comments Generate without header comments
20
+ -h, --help Print usage information
21
+ --version Print version
22
+
23
+ Nidyx generates plain Objective-C models from JSON Schema. It can also generate
24
+ models with JSONModel support.
25
+
26
+ Examples
27
+ ========
28
+
29
+ Bare minimum. Given a schema and a class prefix, generate models in the
30
+ current directory:
31
+
32
+ $ nidyx example.json.schema ClassPrefix
33
+
34
+ Specify an ouput directory:
35
+
36
+ $ nidyx example.json.schema ClassPrefix /path/to/output/directory
37
+
38
+ Generate models with JSONModel support and all optional documentation:
39
+
40
+ $ nidyx example.json.schema ClassPrefix /path/to/output/directory \
41
+ -j -a "Your Name" -c "Company Name" -p "Project Name"
42
+
43
+ ```
44
+
45
+ ## Features
46
+
47
+ __[JSON Schema draft 4][JSONSchemaDraft4] support:__
48
+
49
+ Nidyx exclusively supports JSON Schema draft 4. All previous drafts are not
50
+ supported intentionally.
51
+
52
+ ## Examples
53
+
54
+ Examples are run with the following unless otherwise specified:
55
+
56
+ ```bash
57
+ $ nidyx example.json.schema Example
58
+ ```
59
+
60
+ #### Simple Properties
61
+
62
+ ```json
63
+ {
64
+ "properties": {
65
+ "key": { "type": "string" },
66
+ "value": { "type": "string" }
67
+ }
68
+ }
69
+ ```
70
+
71
+ ```objc
72
+ // ExampleModel.h
73
+ @interface ExampleModel
74
+ @property (strong, nonatomic) NSString* key;
75
+ @property (strong, nonatomic) NSString* value;
76
+ @end
77
+ ```
78
+
79
+ #### Refs and Nested Properties
80
+
81
+ ```json
82
+ {
83
+ "properties": {
84
+ "id": {
85
+ "type": "object",
86
+ "properties": {
87
+ "key": { "type": "string" },
88
+ "hash": { "type": "string" }
89
+ }
90
+ },
91
+ "value": { "$ref": "#/definitions/obj" }
92
+ },
93
+ "definitions": {
94
+ "obj": {
95
+ "type": "object",
96
+ "properties": {
97
+ "banner": { "$ref": "#/definitions/banner" },
98
+ "name": { "type": "string" },
99
+ "count": { "type": "integer" }
100
+ }
101
+ },
102
+ "banner": { "type": "string" }
103
+ }
104
+ }
105
+ ```
106
+
107
+ ```objc
108
+ // ExampleModel.h
109
+ #import "ExampleIdModel.h"
110
+ #import "ExampleObjModel.h"
111
+ @interface ExampleModel
112
+ @property (strong, nonatomic) ExampleIdModel* id;
113
+ @property (strong, nonatomic) ExampleObjModel* value;
114
+ @end
115
+
116
+ // ExampleIdModel.h
117
+ @interface ExampleIdModel
118
+ @property (strong, nonatomic) NSString* key;
119
+ @property (strong, nonatomic) NSString* hash;
120
+ @end
121
+
122
+ // ExampleObjModel.h
123
+ @interface ExampleObjModel
124
+ @property (strong, nonatomic) NSString* banner;
125
+ @property (strong, nonatomic) NSString* name;
126
+ @property (assign, nonatomic) NSInteger count;
127
+ @end
128
+ ```
129
+
130
+ #### Caveats
131
+
132
+ * The following is omitted from the beginning of all JSON examples:
133
+
134
+ ```
135
+ "$schema": "http://json-schema.org/draft-04/schema#",
136
+ "type": "object",
137
+ ```
138
+
139
+ * `.m` files are also omitted from all examples
140
+
141
+ ## License
142
+
143
+ MIT.
144
+
145
+ [JSONSchema]: http://json-schema.org/
146
+ [JSONSchemaDraft4]: http://tools.ietf.org/html/draft-zyp-json-schema-04
data/bin/nidyx ADDED
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "optparse"
4
+ require "nidyx"
5
+ require "nidyx/version"
6
+ require "nidyx/generator"
7
+
8
+ ###
9
+ # help text
10
+ ###
11
+
12
+ BANNER = <<END
13
+ usage: nidyx [-h] [--version]
14
+ nidyx <schema> <class-prefix> [output-directory]
15
+ [-n] [-a author] [-c company] [-p project]
16
+ [--json-model] # objc specific
17
+
18
+ END
19
+
20
+ DESC = <<END
21
+
22
+ Nidyx generates plain Objective-C models from JSON Schema. It can also generate
23
+ models with JSONModel support.
24
+
25
+ Examples
26
+ ========
27
+
28
+ Bare minimum. Given a schema and a class prefix, generate models in the
29
+ current directory:
30
+
31
+ $ nidyx example.json.schema ClassPrefix
32
+
33
+ Specify an ouput directory:
34
+
35
+ $ nidyx example.json.schema ClassPrefix /path/to/output/directory
36
+
37
+ Generate models with JSONModel support and all optional documentation:
38
+
39
+ $ nidyx example.json.schema ClassPrefix /path/to/output/directory \\
40
+ -j -a "Your Name" -c "Company Name" -p "Project Name"
41
+
42
+ END
43
+
44
+ ###
45
+ # option parsing
46
+ ###
47
+
48
+ # defaults
49
+ options = {
50
+ :comments => true,
51
+ :platform => "objc",
52
+ :objc => {
53
+ :json_model => false
54
+ }
55
+ }
56
+
57
+ opts = OptionParser.new do |o|
58
+ o.banner = BANNER
59
+
60
+ ###
61
+ # general generation options
62
+ ###
63
+
64
+ o.on("-a", "--author AUTHOR", "Author's name") do |a|
65
+ options[:author] = a
66
+ end
67
+
68
+ o.on("-c", "--company COMPANY", "Company's name") do |c|
69
+ options[:company] = c
70
+ end
71
+
72
+ o.on("-p", "--project PROJECT", "Project's name") do |p|
73
+ options[:project] = p
74
+ end
75
+
76
+ o.on("-n", "--no-comments", "Generate without header comments") do |n|
77
+ options[:comments] = false
78
+ end
79
+
80
+ ###
81
+ # objc generation options
82
+ ###
83
+
84
+ o.on("--json-model", "Generate with JSONModel support") do |j|
85
+ options[:objc][:json_model] = true
86
+ end
87
+
88
+ ###
89
+ # other
90
+ ###
91
+
92
+ o.on("-h", "--help", "Print usage information") do
93
+ puts o
94
+ exit
95
+ end
96
+
97
+ o.on("--version", "Print version") do
98
+ puts Nidyx::VERSION
99
+ exit
100
+ end
101
+
102
+ o.separator DESC
103
+ end
104
+
105
+ begin
106
+ opts.parse!
107
+ rescue OptionParser::InvalidOption => e
108
+ puts e
109
+ puts opts
110
+ exit 1
111
+ end
112
+
113
+ if ARGV.size < 2
114
+ puts "Too few arguments." unless ARGV.empty?
115
+ puts opts
116
+ exit 1
117
+ end
118
+
119
+ options[:output_path] = ARGV[2]
120
+
121
+ ###
122
+ # run
123
+ ###
124
+
125
+ Nidyx::Generator.run(ARGV[0], ARGV[1], options)
@@ -0,0 +1,54 @@
1
+ module Nidyx
2
+ module Common
3
+ class NoObjectAtPathError < StandardError; end
4
+
5
+ CLASS_SUFFIX = "Model"
6
+ IGNORED_KEYS = "properties", "definitions"
7
+
8
+ def class_name(prefix, key)
9
+ if key
10
+ prefix + key.camelize + CLASS_SUFFIX
11
+ else
12
+ prefix + CLASS_SUFFIX
13
+ end
14
+ end
15
+
16
+ def class_name_from_path(prefix, path, schema)
17
+ override = object_at_path(path, schema)[NAME_OVERRIDE_KEY]
18
+ return class_name(prefix, override.camelize) if override
19
+
20
+ name = ""
21
+ path.each_index do |idx|
22
+ # skip ignored keys such as "properties" in the name
23
+ next if IGNORED_KEYS.include?(path[idx])
24
+ # skip the last key if we are using an override
25
+ next if override && (idx == path.length - 1)
26
+
27
+ obj = object_at_path(path[0..idx], schema)
28
+ if obj[NAME_OVERRIDE_KEY]
29
+ name << obj[NAME_OVERRIDE_KEY].camelize
30
+ else
31
+ name << path[idx].camelize
32
+ end
33
+ end
34
+
35
+ # append the override name to the end if present
36
+ name << override.camelize if override
37
+ class_name(prefix, name)
38
+ end
39
+
40
+ def object_at_path(path, schema)
41
+ obj = schema
42
+
43
+ begin
44
+ path.each { |p| obj = obj[p] }
45
+ rescue
46
+ raise NoObjectAtPathError, path
47
+ end
48
+
49
+ raise NoObjectAtPathError, path unless obj
50
+
51
+ obj
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,12 @@
1
+ class String
2
+ # Inspired by (read: "Stolen from") Rails ActiveSupport::Inflector
3
+ def camelize(uppercase_first_letter = true)
4
+ s = self
5
+ if uppercase_first_letter
6
+ s = s.sub(/^[a-z\d]*/) { $&.capitalize }
7
+ else
8
+ s = s.sub(/^([A-Z_]|\w)/) { $&.downcase }
9
+ end
10
+ s.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ require 'nidyx/reader'
2
+ require 'nidyx/parser'
3
+ require 'nidyx/mapper'
4
+ require 'nidyx/output'
5
+
6
+ module Nidyx
7
+ module Generator
8
+ extend self
9
+
10
+ def run(schema_path, model_prefix, options)
11
+ schema = Nidyx::Reader.read(schema_path)
12
+ raw_models = Nidyx::Parser.parse(model_prefix, schema, options)
13
+ models = Nidyx::Mapper.map(raw_models, options)
14
+ Nidyx::Output.write(models, options[:output_path])
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ require 'nidyx/objc/mapper'
2
+
3
+ module Nidyx
4
+ module Mapper
5
+ extend self
6
+
7
+ # Proxies model mapping to the proper platform mapper
8
+ # @param models [Hash] a hash with model name keys and Model values
9
+ # @param options [Hash] runtime options
10
+ # @return [Array] an array of models generated for a specific platform
11
+ def map(models, options)
12
+ models = models.values
13
+ case options[:platform].downcase
14
+ when "objc", "obj-c", "objective-c"
15
+ Nidyx::ObjCMapper.map(models, options)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ module Nidyx
2
+ class Model
3
+ attr_accessor :properties, :dependencies
4
+ attr_reader :name
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ @properties = []
9
+ @dependencies = Set.new
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,33 @@
1
+ require "nidyx/objc/model_base"
2
+
3
+ module Nidyx
4
+ class ObjCImplementation < ObjCModelBase
5
+ self.template_file = File.join(self.template_path, "implementation.mustache")
6
+
7
+ attr_accessor :name_overrides
8
+
9
+ def initialize(name, options)
10
+ super
11
+ self.file_name = "#{name}.#{EXT}"
12
+ self.imports = [name]
13
+ end
14
+
15
+ def name_overrides?
16
+ !self.name_overrides.empty?
17
+ end
18
+
19
+ def name_override_string
20
+ string = ""
21
+ count = 0
22
+ name_overrides.each do |original, override|
23
+ count += 1
24
+ string += "@\"#{original}\": @\"#{override}\""
25
+ string += ",\n" unless count == name_overrides.length
26
+ end
27
+ string
28
+ end
29
+
30
+ private
31
+ EXT = "m"
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ require "nidyx/objc/model_base"
2
+
3
+ module Nidyx
4
+ class ObjCInterface < ObjCModelBase
5
+ attr_accessor :properties
6
+
7
+ self.template_file = File.join(self.template_path, "interface.mustache")
8
+
9
+ def initialize(name, options)
10
+ super
11
+ self.file_name = "#{name}.#{EXT}"
12
+ self.imports << JSON_MODEL_IMPORT if self.json_model
13
+ end
14
+
15
+ private
16
+ EXT = "h"
17
+ JSON_MODEL_IMPORT = "JSONModel"
18
+
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ require "set"
2
+ require "nidyx/objc/model"
3
+ require "nidyx/objc/interface"
4
+ require "nidyx/objc/implementation"
5
+ require "nidyx/objc/property"
6
+
7
+ module Nidyx
8
+ module ObjCMapper
9
+ extend self
10
+
11
+ # Generates a list of ObjCModels
12
+ # @param models [Array] an array of generic Models to map
13
+ # @param options [Hash] runtime options
14
+ # @return [Array] a list of ObjCModels
15
+ def map(models, options)
16
+ objc_models = []
17
+
18
+ models.each do |m|
19
+ interface = map_interface(m, options)
20
+ implementation = map_implementation(m, options)
21
+ objc_models << Nidyx::ObjCModel.new(interface, implementation)
22
+ end
23
+
24
+ objc_models
25
+ end
26
+
27
+ private
28
+
29
+ def map_interface(model, options)
30
+ interface = Nidyx::ObjCInterface.new(model.name, options)
31
+ interface.properties = model.properties.map { |p| Nidyx::ObjCProperty.new(p) }
32
+ interface.imports += model.dependencies.to_a
33
+ interface
34
+ end
35
+
36
+ def map_implementation(model, options)
37
+ implementation = Nidyx::ObjCImplementation.new(model.name, options)
38
+ name_overrides = {}
39
+ model.properties.each { |p| name_overrides[p.overriden_name] = p.name if p.overriden_name }
40
+ implementation.name_overrides = name_overrides
41
+ implementation
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,12 @@
1
+ module Nidyx
2
+ class ObjCModel
3
+ def initialize(interface, implementation)
4
+ @interface = interface
5
+ @implementation = implementation
6
+ end
7
+
8
+ def files
9
+ [@interface, @implementation]
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,31 @@
1
+ require "mustache"
2
+
3
+ module Nidyx
4
+ class ObjCModelBase < Mustache
5
+ attr_accessor :name, :file_name, :author, :owner, :project, :imports, :comments, :json_model
6
+
7
+ self.template_path = File.join(__FILE__, "../../../../templates/objc")
8
+
9
+ def initialize(name, options)
10
+ @name = name
11
+ @author = options[:author]
12
+ @owner = options[:company]
13
+ @project = options[:project]
14
+ @comments = options[:comments]
15
+ @json_model = options[:objc][:json_model] if options[:objc]
16
+ @imports = []
17
+ end
18
+
19
+ def has_imports?
20
+ !self.imports.empty?
21
+ end
22
+
23
+ def no_owner?
24
+ !self.owner
25
+ end
26
+
27
+ def json_model?
28
+ self.json_model
29
+ end
30
+ end
31
+ end