nitron 0.2

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.
@@ -0,0 +1,2 @@
1
+ .repl_history
2
+ build
@@ -0,0 +1,83 @@
1
+ Nitron
2
+ ===================
3
+
4
+ Introduction
5
+ ----------
6
+ Nitron is an opinionated, loosely-coupled set of RubyMotion components designed to accelerate iOS
7
+ development, especially with simpler iOS apps. It provides meaningful
8
+ abstractions atop the strong foundation present in the iOS SDK.
9
+
10
+ This first release focuses on making Storyboard-based workflows enjoyable.
11
+
12
+ Installation
13
+ ----------
14
+ Add the following line to your `Gemfile`:
15
+
16
+ `gem "nitron"`
17
+
18
+ If you haven't already, update your Rakefile to use Bundler. Insert the
19
+ following immediately before `Motion::Project::App.setup`:
20
+
21
+ ```ruby
22
+ require 'rubygems'
23
+ require 'bundler'
24
+
25
+ Bundler.require
26
+ ```
27
+
28
+ Example
29
+ ------
30
+ A modal view controller responsible for creating new `Tasks`:
31
+
32
+ ```ruby
33
+ class TaskCreateViewController < Nitron::ViewController
34
+ # The on class method is part of Nitron's Action DSL.
35
+ # It wires the provided block to be an event handler for the specified outlet using the iOS target/action pattern.
36
+ on :cancel do
37
+ close
38
+ end
39
+
40
+ # Nitron emulates 'native' outlet support, allowing you to easily define outlets through Xcode.
41
+ # The titleField and datePicker methods are created upon initial load by using metadata contained in the Storyboard.
42
+ on :save do
43
+ Task.create(title: titleField.text, due: datePicker.date)
44
+
45
+ close
46
+ end
47
+ end
48
+ ```
49
+
50
+ Features
51
+ ----------
52
+
53
+ * **Data Binding** - declaratively bind your model data to controls, either
54
+ via code or Interface Builder
55
+ * **Outlet Support** - expose controls to your controllers via Interface Builder
56
+ * **Action Support** - Ruby DSL to attach event handlers to outlets
57
+ * **CoreData Models** - beginnings of a CoreData model abstraction uses
58
+ XCode's data modeling tools with an ActiveRecord-like syntax
59
+
60
+ If you notice, many of these features aim at slimming down your
61
+ controllers. This is no accident: many iOS controllers have far too many
62
+ responsibilities. Glue code is a perfect target for metaprogramming, so
63
+ we're focusing on making beautiful controllers presently.
64
+
65
+ We're also careful to make these features modular, so you can mix them
66
+ into your existing controllers as needed.
67
+
68
+ Tutorial
69
+ ----------
70
+ TBD
71
+
72
+ Examples
73
+ ----------
74
+ https://github.com/mattgreen/nitron-examples
75
+
76
+ Caveats
77
+ ---------
78
+
79
+ * Data binding doesn't use KVO presently. This is already in the works.
80
+ * Action support is limited to selecting a button or a table cell.
81
+ Future releases will expand the DSL to support additional events.
82
+ * CoreData needs support for relationships and migrations.
83
+
@@ -0,0 +1,20 @@
1
+ require 'nitron/version'
2
+
3
+ unless defined?(Motion::Project::Config)
4
+ raise "This file must be required within a RubyMotion project Rakefile."
5
+ end
6
+
7
+ Motion::Project::App.setup do |app|
8
+ Dir.glob(File.join(File.dirname(__FILE__), "nitron/**/*.rb")).each do |file|
9
+ app.files.unshift(file)
10
+ end
11
+
12
+ app.files.unshift(File.join(File.dirname(__FILE__), 'nitron/view_controller.rb'))
13
+ app.files.unshift(File.join(File.dirname(__FILE__), 'nitron/ui/data_binding_support.rb'))
14
+ app.files.unshift(File.join(File.dirname(__FILE__), 'nitron/ui/outlet_support.rb'))
15
+ app.files.unshift(File.join(File.dirname(__FILE__), 'nitron/ui/action_support.rb'))
16
+
17
+ unless app.frameworks.include?("CoreData")
18
+ app.frameworks << "CoreData"
19
+ end
20
+ end
@@ -0,0 +1,43 @@
1
+ class AppDelegate
2
+ def managedObjectContext
3
+ @managedObjectContext ||= begin
4
+ applicationName = NSBundle.mainBundle.infoDictionary.objectForKey("CFBundleName")
5
+
6
+ documentsDirectory = NSFileManager.defaultManager.URLsForDirectory(NSDocumentDirectory, inDomains:NSUserDomainMask).lastObject;
7
+ storeURL = documentsDirectory.URLByAppendingPathComponent("#{applicationName}.sqlite")
8
+
9
+ error_ptr = Pointer.new(:object)
10
+ unless persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration:nil, URL:storeURL, options:nil, error:error_ptr)
11
+ raise "Can't add persistent SQLite store: #{error_ptr[0].description}"
12
+ end
13
+
14
+ context = NSManagedObjectContext.alloc.init
15
+ context.persistentStoreCoordinator = persistentStoreCoordinator
16
+
17
+ context
18
+ end
19
+ end
20
+
21
+ def managedObjectModel
22
+ @managedObjectModel ||= begin
23
+ model = NSManagedObjectModel.mergedModelFromBundles([NSBundle.mainBundle]).mutableCopy
24
+
25
+ model.entities.each do |entity|
26
+ begin
27
+ Kernel.const_get(entity.name)
28
+ entity.setManagedObjectClassName(entity.name)
29
+
30
+ rescue NameError
31
+ entity.setManagedObjectClassName("Model")
32
+ end
33
+ end
34
+
35
+ model
36
+ end
37
+ end
38
+
39
+ def persistentStoreCoordinator
40
+ @coordinator ||= NSPersistentStoreCoordinator.alloc.initWithManagedObjectModel(managedObjectModel)
41
+ end
42
+ end
43
+
@@ -0,0 +1,100 @@
1
+ module Nitron
2
+ class Model < NSManagedObject
3
+ class << self
4
+ def all
5
+ Data::Relation.alloc.initWithClass(self)
6
+ end
7
+
8
+ def create(attributes={})
9
+ model = new(attributes)
10
+ model.save
11
+
12
+ model
13
+ end
14
+
15
+ def destroy(object)
16
+ if context = object.managedObjectContext
17
+ context.deleteObject(object)
18
+
19
+ error = Pointer.new(:object)
20
+ context.save(error)
21
+ end
22
+ end
23
+
24
+ def entityDescription
25
+ @_metadata ||= UIApplication.sharedApplication.delegate.managedObjectModel.entitiesByName[name]
26
+ end
27
+
28
+ def find(object_id)
29
+ unless entity = find_by_id(object_id)
30
+ raise "No record found!"
31
+ end
32
+
33
+ entity
34
+ end
35
+
36
+ def first
37
+ relation.first
38
+ end
39
+
40
+ def method_missing(method, *args, &block)
41
+ if method.start_with?("find_by_")
42
+ attribute = method.gsub("find_by_", "")
43
+ relation.where("#{attribute} = ?", *args).first
44
+ else
45
+ super
46
+ end
47
+ end
48
+
49
+ def new(attributes={})
50
+ self.alloc.initWithEntity(entityDescription, insertIntoManagedObjectContext:nil).tap do |model|
51
+ attributes.each do |keyPath, value|
52
+ model.setValue(value, forKey:keyPath)
53
+ end
54
+ end
55
+ end
56
+
57
+ def respond_to?(method)
58
+ if method.start_with?("find_by_")
59
+ true
60
+ else
61
+ super
62
+ end
63
+ end
64
+
65
+ def order(*args)
66
+ relation.order(*args)
67
+ end
68
+
69
+ def where(*args)
70
+ relation.where(*args)
71
+ end
72
+
73
+ private
74
+
75
+ def relation
76
+ Data::Relation.alloc.initWithClass(self)
77
+ end
78
+ end
79
+
80
+ def destroy
81
+ self.class.destroy(self)
82
+ end
83
+
84
+ def inspect
85
+ properties = entity.properties.map { |property| "#{property.name}: #{valueForKey(property.name).inspect}" }
86
+
87
+ "#<#{entity.name} #{properties.join(", ")}>"
88
+ end
89
+
90
+ def save
91
+ unless context = managedObjectContext
92
+ context = UIApplication.sharedApplication.delegate.managedObjectContext
93
+ context.insertObject(self)
94
+ end
95
+
96
+ error = Pointer.new(:object)
97
+ context.save(error)
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,59 @@
1
+ module Nitron
2
+ module Data
3
+ class Relation < NSFetchRequest
4
+ def initWithClass(entityClass)
5
+ if init
6
+ setEntity(entityClass.entityDescription)
7
+ end
8
+
9
+ self
10
+ end
11
+
12
+ def all
13
+ self
14
+ end
15
+
16
+ def first
17
+ setFetchLimit(1)
18
+
19
+ to_a[0]
20
+ end
21
+
22
+ def inspect
23
+ to_a
24
+ end
25
+
26
+ def order(column, opts={})
27
+ descriptors = sortDescriptors || []
28
+
29
+ descriptors << NSSortDescriptor.alloc.initWithKey(column.to_s, ascending:opts.fetch(:ascending, true))
30
+ setSortDescriptors(descriptors)
31
+
32
+ self
33
+ end
34
+
35
+ def to_a
36
+ error = Pointer.new(:object)
37
+ context.executeFetchRequest(self, error:error)
38
+ end
39
+
40
+ def where(format, *args)
41
+ predicate = NSPredicate.predicateWithFormat(format.gsub("?", "%@"), argumentArray:args)
42
+
43
+ if self.predicate
44
+ self.predicate = NSCompoundPredicate.andPredicateWithSubpredicates([predicate])
45
+ else
46
+ self.predicate = predicate
47
+ end
48
+
49
+ self
50
+ end
51
+
52
+ private
53
+
54
+ def context
55
+ UIApplication.sharedApplication.delegate.managedObjectContext
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,38 @@
1
+ module Nitron
2
+ class StaticTableViewController < ViewController
3
+ def setValue(value, forKey: key)
4
+ if key == "staticDataSource"
5
+ @_dataSource = value
6
+ else
7
+ super
8
+ end
9
+ end
10
+
11
+ def tableView(tableView, didSelectRowAtIndexPath:indexPath)
12
+ cell = tableView.cellForRowAtIndexPath(indexPath)
13
+
14
+ if outlet = cell.outlets.first
15
+ handler = self.class.outletHandlers[outlet[0]]
16
+
17
+ if handler
18
+ self.instance_eval(&handler[:handler])
19
+ end
20
+ end
21
+ end
22
+
23
+ def tableView(tableView, heightForRowAtIndexPath:indexPath)
24
+ cell = @_dataSource.tableView(tableView, cellForRowAtIndexPath:indexPath)
25
+
26
+ cell.bounds.size.height
27
+ end
28
+
29
+ def viewWillAppear(animated)
30
+ view.dataSource = @_dataSource
31
+ view.delegate = self
32
+
33
+ # The data binding module may wrap view.delegate, so run it after we've set up.
34
+ super
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,172 @@
1
+ module Nitron
2
+ class TableViewController < ViewController
3
+ def self.collection(&block)
4
+ options[:collection] = block
5
+ end
6
+
7
+ def self.group_by(name, opts={})
8
+ options[:groupBy] = name.to_s
9
+ options[:groupIndex] = opts[:index] || false
10
+ end
11
+
12
+ def self.options
13
+ @options ||= {
14
+ collection: lambda { [] },
15
+ groupBy: nil,
16
+ groupIndex: false,
17
+ }
18
+ end
19
+
20
+ protected
21
+
22
+ def controllerDidChangeContent(controller)
23
+ view.reloadData()
24
+ end
25
+
26
+ def dataSource
27
+ @_dataSource ||= begin
28
+ collection = self.instance_eval(&self.class.options[:collection])
29
+
30
+ case collection
31
+ when Array
32
+ ArrayDataSource.alloc.initWithCollection(collection, className:self.class.name)
33
+ when NSFetchRequest
34
+ CoreDataSource.alloc.initWithRequest(collection, owner:self, sectionNameKeyPath:self.class.options[:groupBy], options:self.class.options)
35
+ else
36
+ raise "Collection block must return an Array, or an NSFetchRequest"
37
+ end
38
+ end
39
+ end
40
+
41
+ def prepareForSegue(segue, sender:sender)
42
+ model = nil
43
+
44
+ if view.respond_to?(:indexPathForSelectedRow)
45
+ if view.indexPathForSelectedRow
46
+ model = dataSource.objectAtIndexPath(view.indexPathForSelectedRow)
47
+ end
48
+ end
49
+
50
+ if model
51
+ controller = segue.destinationViewController
52
+ if controller.respond_to?(:model=)
53
+ controller.model = model
54
+ end
55
+ end
56
+ end
57
+
58
+ def setValue(value, forKey: key)
59
+ if key == "staticDataSource"
60
+ raise "Static tables are not supported by TableViewController! Please use StaticTableViewController instead."
61
+ else
62
+ super
63
+ end
64
+ end
65
+
66
+ def viewDidLoad
67
+ super
68
+
69
+ view.dataSource = dataSource
70
+ end
71
+
72
+ protected
73
+
74
+ class ArrayDataSource
75
+ def initWithCollection(collection, className:className)
76
+ if init
77
+ @collection = collection
78
+ @className = className
79
+ end
80
+
81
+ self
82
+ end
83
+
84
+ def numberOfSectionsInTableView(tableView)
85
+ 1
86
+ end
87
+
88
+ def objectAtIndexPath(indexPath)
89
+ @collection[indexPath.row]
90
+ end
91
+
92
+ def sectionForSectionIndexTitle(title, atIndex:index)
93
+ nil
94
+ end
95
+
96
+ def tableView(tableView, cellForRowAtIndexPath:indexPath)
97
+ @cellReuseIdentifier ||= "#{@className.gsub("ViewController", "")}Cell"
98
+ unless cell = tableView.dequeueReusableCellWithIdentifier(@cellReuseIdentifier)
99
+ puts "Unable to find a cell named #{@cellReuseIdentifier}. Have you set the reuse identifier of the UITableViewCell?"
100
+ return
101
+ end
102
+
103
+ cell
104
+ end
105
+
106
+ def tableView(tableView, numberOfRowsInSection:section)
107
+ @collection.size
108
+ end
109
+ end
110
+
111
+ class CoreDataSource
112
+ def initWithRequest(request, owner:owner, sectionNameKeyPath:sectionNameKeyPath, options:options)
113
+ if init
114
+ context = UIApplication.sharedApplication.delegate.managedObjectContext
115
+
116
+ @className = owner.class.name
117
+ @controller = NSFetchedResultsController.alloc.initWithFetchRequest(request,
118
+ managedObjectContext:context,
119
+ sectionNameKeyPath:sectionNameKeyPath,
120
+ cacheName:nil)
121
+ @controller.delegate = owner
122
+ @options = options
123
+
124
+ errorPtr = Pointer.new(:object)
125
+ unless @controller.performFetch(errorPtr)
126
+ raise "Error fetching data"
127
+ end
128
+ end
129
+
130
+ self
131
+ end
132
+
133
+ def numberOfSectionsInTableView(tableView)
134
+ @controller.sections.size
135
+ end
136
+
137
+ def objectAtIndexPath(indexPath)
138
+ @controller.objectAtIndexPath(indexPath)
139
+ end
140
+
141
+ def sectionForSectionIndexTitle(title, atIndex:index)
142
+ @collection.sectionForSectionIndexTitle(title, atIndex:index)
143
+ end
144
+
145
+ def sectionIndexTitlesForTableView(tableView)
146
+ if @options[:groupIndex]
147
+ @controller.sectionIndexTitles
148
+ else
149
+ nil
150
+ end
151
+ end
152
+
153
+ def tableView(tableView, cellForRowAtIndexPath:indexPath)
154
+ @cellReuseIdentifier ||= "#{@className.gsub("ViewController", "")}Cell"
155
+ unless cell = tableView.dequeueReusableCellWithIdentifier(@cellReuseIdentifier)
156
+ puts "Unable to find a cell named #{@cellReuseIdentifier}. Have you set the reuse identifier of the UITableViewCell?"
157
+ return nil
158
+ end
159
+
160
+ cell
161
+ end
162
+
163
+ def tableView(tableView, numberOfRowsInSection:section)
164
+ @controller.sections[section].numberOfObjects
165
+ end
166
+
167
+ def tableView(tableView, titleForHeaderInSection:section)
168
+ @controller.sections[section].name
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,49 @@
1
+ module Nitron
2
+ module UI
3
+ module ActionSupport
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def on(outlet, &block)
10
+ actions[outlet.to_s] = { :handler => block }
11
+ end
12
+
13
+ def actions
14
+ @_actions ||= {
15
+ "cancel" => { :handler => proc { close }, :default => true },
16
+ "done" => { :handler => proc { close }, :default => true }
17
+ }
18
+ end
19
+ end
20
+
21
+ def _dispatch(sender)
22
+ if action = @_actions[sender]
23
+ instance_eval &action[:handler]
24
+ end
25
+ end
26
+
27
+ def dealloc
28
+ @_actions.clear
29
+
30
+ super
31
+ end
32
+
33
+ def viewDidLoad
34
+ super
35
+
36
+ @_actions = {}
37
+
38
+ self.class.actions.each do |outlet, action|
39
+ if respond_to?(outlet)
40
+ target = send(outlet)
41
+ @_actions[target] = self.class.actions[outlet]
42
+
43
+ target.addTarget(self, action:"_dispatch:", forControlEvents:UIControlEventTouchUpInside)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,49 @@
1
+ module Nitron
2
+ module UI
3
+ class DataBinder
4
+ def self.shared
5
+ @singleton ||= alloc.init
6
+ end
7
+
8
+ def bind(model, view, options={})
9
+ if view.is_a?(UITableView)
10
+ view.delegate = DataBoundTableDelegate.alloc.initWithDelegate(view.delegate)
11
+ return [view.delegate]
12
+ end
13
+
14
+ view.dataBindings.each do |keyPath, subview|
15
+ bindControl(model, subview, keyPath)
16
+ end
17
+
18
+ nil
19
+ end
20
+
21
+ private
22
+
23
+ def bindControl(model, control, keyPath)
24
+ value = model.valueForKeyPath(keyPath)
25
+
26
+ if control.respond_to?(:text=)
27
+ control.text = value
28
+ elsif control.respond_to?(:image=)
29
+ control.image = value
30
+ elsif control.respond_to?(:value=)
31
+ control.value = value
32
+ elsif control.respond_to?(:on=)
33
+ control.on = value
34
+ elsif control.respond_to?(:progress=)
35
+ control.progress = value
36
+ elsif control.respond_to?(:date=)
37
+ control.date = value
38
+ else
39
+ puts "Sorry, data binding is not supported for an instance of '#{control.class.name}' :("
40
+ end
41
+
42
+ rescue
43
+ puts "***ERROR: Failed to bind value #{value.inspect} (read from '#{model.class.name}.#{keyPath}') to #{control.inspect}"
44
+
45
+ raise
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,33 @@
1
+ module Nitron
2
+ module UI
3
+ module DataBindingSupport
4
+ def dealloc
5
+ if @_bindings
6
+ @_bindings = nil
7
+ end
8
+
9
+ if @_model
10
+ @_model = nil
11
+ end
12
+
13
+ super
14
+ end
15
+
16
+ def model
17
+ @_model
18
+ end
19
+
20
+ def model=(model)
21
+ @_model = model
22
+
23
+ DataBinder.shared.bind(model, view)
24
+ end
25
+
26
+ def viewDidLoad
27
+ super
28
+
29
+ @_bindings = DataBinder.shared.bind(model, view)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,41 @@
1
+ module Nitron
2
+ module UI
3
+ class DataBoundTableDelegate
4
+ def initWithDelegate(delegate)
5
+ if init
6
+ @delegate = delegate
7
+ end
8
+
9
+ self
10
+ end
11
+
12
+ def method_missing(method, *args, &block)
13
+ if @delegate
14
+ @delegate.send(method, *args, &block)
15
+ else
16
+ super
17
+ end
18
+ end
19
+
20
+ def respond_to?(method)
21
+ if method == "tableView:willDisplayCell:forRowAtIndexPath"
22
+ true
23
+ elsif @delegate
24
+ @delegate.respond_to?(method)
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ def tableView(tableView, willDisplayCell:cell, forRowAtIndexPath:indexPath)
31
+ if @delegate && @delegate.respond_to?("tableView:willDisplayCell:forRowAtIndexPath:")
32
+ @delegate.tableView(tableView, willDisplayCell:cell, forRowAtIndexPath:indexPath)
33
+ end
34
+
35
+ model = tableView.dataSource.objectAtIndexPath(indexPath)
36
+
37
+ Nitron::UI::DataBinder.shared.bind(model, cell)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,19 @@
1
+ class AppDelegate
2
+ def application(application, didFinishLaunchingWithOptions:launchOptions)
3
+ @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
4
+
5
+ if storyboard
6
+ @window.rootViewController = storyboard.instantiateInitialViewController
7
+ end
8
+
9
+ @window.rootViewController.wantsFullScreenLayout = true
10
+ @window.makeKeyAndVisible
11
+
12
+ true
13
+ end
14
+
15
+ def storyboard
16
+ @storyboard ||= UIStoryboard.storyboardWithName("MainStoryboard", bundle:nil)
17
+ end
18
+ end
19
+
@@ -0,0 +1,9 @@
1
+ class UIBarButtonItem
2
+ def setValue(value, forUndefinedKey:key)
3
+ if key == "outlet"
4
+ view.setValue(value, forUndefinedKey:key)
5
+ else
6
+ super
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ class UIView
2
+ def dataBindings
3
+ @_dataBindings ||= {}
4
+ end
5
+
6
+ def outlets
7
+ @_outlets ||= {}
8
+ end
9
+
10
+ def setValue(value, forUndefinedKey:key)
11
+ if key == "dataBinding" || key == "outlet"
12
+ raise "Runtime attribute '#{key}' must be a String (declared on #{self.class.name})" unless value.is_a?(String)
13
+
14
+ container = self
15
+ while container.superview
16
+ container = container.superview
17
+ end
18
+
19
+ if key == "dataBinding"
20
+ unless value.start_with?("model.")
21
+ raise "Data binding expression must start with 'model.'; you provided '#{value}'"
22
+ end
23
+
24
+ container.dataBindings[value[6..-1]] = self
25
+ else
26
+ container.outlets[value] = self
27
+ end
28
+ else
29
+ super
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,12 @@
1
+ module Nitron
2
+ module UI
3
+ class OutletBinder
4
+ def bind(controller, view)
5
+ # Emulate IB's outlets by using KVC.
6
+ view.outlets.each do |outlet, subview|
7
+ controller.setValue(subview, forKey:outlet)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ module Nitron
2
+ module UI
3
+ module OutletSupport
4
+ def setValue(value, forUndefinedKey:key)
5
+ unless self.class.respond_to?(key)
6
+ self.class.send(:attr_reader, key)
7
+ end
8
+
9
+ instance_variable_set("@#{key}", value)
10
+ end
11
+
12
+ def viewDidLoad
13
+ super
14
+
15
+ outletBinder = OutletBinder.new
16
+ outletBinder.bind(self, view)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module Nitron
2
+ VERSION = "0.2"
3
+ end
@@ -0,0 +1,12 @@
1
+ module Nitron
2
+ class ViewController < UIViewController
3
+ include UI::DataBindingSupport
4
+ include UI::OutletSupport
5
+ include UI::ActionSupport
6
+
7
+ def close
8
+ dismissModalViewControllerAnimated(true)
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/nitron/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Matt Green"]
6
+ gem.email = ["mattgreenrocks@gmail.com"]
7
+ gem.description = "Turbocharged iOS development via RubyMotion"
8
+ gem.summary = "Turbocharged iOS development via RubyMotion"
9
+ gem.homepage = "https://github.com/mattgreen/nitron"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
13
+ gem.name = "nitron"
14
+ gem.require_paths = ["lib"]
15
+ gem.version = Nitron::VERSION
16
+
17
+ gem.add_dependency 'motion-cocoapods', '>= 1.0.1'
18
+ end
@@ -0,0 +1,9 @@
1
+ describe "Application 'spry'" do
2
+ before do
3
+ @app = UIApplication.sharedApplication
4
+ end
5
+
6
+ it "has one window" do
7
+ @app.windows.size.should == 1
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nitron
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ version: "0.2"
9
+ platform: ruby
10
+ authors:
11
+ - Matt Green
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2012-06-12 00:00:00 -04:00
17
+ default_executable:
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: motion-cocoapods
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ segments:
27
+ - 1
28
+ - 0
29
+ - 1
30
+ version: 1.0.1
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ description: Turbocharged iOS development via RubyMotion
34
+ email:
35
+ - mattgreenrocks@gmail.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - .gitignore
44
+ - README.md
45
+ - lib/nitron.rb
46
+ - lib/nitron/data/extensions/app_delegate+core_data.rb
47
+ - lib/nitron/data/model.rb
48
+ - lib/nitron/data/relation.rb
49
+ - lib/nitron/static_table_view_controller.rb
50
+ - lib/nitron/table_view_controller.rb
51
+ - lib/nitron/ui/action_support.rb
52
+ - lib/nitron/ui/data_binder.rb
53
+ - lib/nitron/ui/data_binding_support.rb
54
+ - lib/nitron/ui/data_bound_table_delegate.rb
55
+ - lib/nitron/ui/extensions/app_delegate+storyboard.rb
56
+ - lib/nitron/ui/extensions/ui_bar_button_item.rb
57
+ - lib/nitron/ui/extensions/ui_view.rb
58
+ - lib/nitron/ui/outlet_binder.rb
59
+ - lib/nitron/ui/outlet_support.rb
60
+ - lib/nitron/version.rb
61
+ - lib/nitron/view_controller.rb
62
+ - nitron.gemspec
63
+ - spec/main_spec.rb
64
+ has_rdoc: true
65
+ homepage: https://github.com/mattgreen/nitron
66
+ licenses: []
67
+
68
+ post_install_message:
69
+ rdoc_options: []
70
+
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ segments:
85
+ - 0
86
+ version: "0"
87
+ requirements: []
88
+
89
+ rubyforge_project:
90
+ rubygems_version: 1.3.6
91
+ signing_key:
92
+ specification_version: 3
93
+ summary: Turbocharged iOS development via RubyMotion
94
+ test_files:
95
+ - spec/main_spec.rb