motion-pixate-layout 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.
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.md +21 -0
- data/README.md +82 -0
- data/Rakefile +14 -0
- data/app/app_delegate.rb +5 -0
- data/lib/motion-pixate-layout.rb +23 -0
- data/lib/motion-pixate-layout/layout.rb +60 -0
- data/lib/motion-pixate-layout/selector.rb +19 -0
- data/lib/motion-pixate-layout/version.rb +3 -0
- data/lib/motion-pixate-layout/z_core_extensions/ui_view_controller.rb +55 -0
- data/motion-pixate-layout.gemspec +20 -0
- data/spec/lib/layout_spec.rb +59 -0
- data/spec/lib/selector_spec.rb +17 -0
- metadata +111 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
motion-pixate-layout (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
bacon (1.1.0)
|
10
|
+
motion-pixate (1.2)
|
11
|
+
sass
|
12
|
+
rake (10.0.4)
|
13
|
+
sass (3.2.7)
|
14
|
+
|
15
|
+
PLATFORMS
|
16
|
+
ruby
|
17
|
+
|
18
|
+
DEPENDENCIES
|
19
|
+
bacon
|
20
|
+
motion-pixate
|
21
|
+
motion-pixate-layout!
|
22
|
+
rake
|
data/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright 2013 Terrible Labs, Inc.
|
2
|
+
http://terriblelabs.com/
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# MotionPixateLayout
|
2
|
+
|
3
|
+
This project adds a simple DSL to your Rubymotion UIViewControllers to create subviews to be styled with [Pixate](http://www.pixate.com/).
|
4
|
+
|
5
|
+
The idea is inspired by [Teacup](https://github.com/rubymotion/teacup), which has an awesome layout/subview DSL for layout out your controllers. While this DSL is great, Teacup brings in a lot of style/stylesheet features that are not useful to Pixate users. MotionPixateLayout also adds a convenient shorthand selector to quickly set the styleId and styleClass of subviews.
|
6
|
+
|
7
|
+
## A quick example
|
8
|
+
|
9
|
+
````ruby
|
10
|
+
class MyViewController < UIViewController
|
11
|
+
pixate_layout '#my-view.fancy' do
|
12
|
+
UILabel '#title-label.small.green', text: 'My Title'
|
13
|
+
UIButton '#ok-button.call-to-action'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
````
|
17
|
+
|
18
|
+
This code hooks into UIViewController's `viewDidLoad` mode and:
|
19
|
+
|
20
|
+
1. Sets `view.styleId` to 'my-view'
|
21
|
+
1. Sets `view.styleClass` to 'fancy'
|
22
|
+
1. Adds a UILabel with these attributes as a subview of the controller's view:
|
23
|
+
* styleId: 'title-label'
|
24
|
+
* styleClass: 'small green'
|
25
|
+
* text: 'My Title'
|
26
|
+
1. Adds a UIButton with these attributes as a subview of the controller's view:
|
27
|
+
* styleId: 'ok-button'
|
28
|
+
* styleClass: 'call-to-action'
|
29
|
+
|
30
|
+
## Accessing subviews
|
31
|
+
|
32
|
+
MotionPixateLayout adds a `subviews` accessor to UIViewController that returns a hash of the controller's main view's subviews, where the keys are the styleId of the subview. To set the text of the title-label in the above example, we can access the subview by its id:
|
33
|
+
|
34
|
+
````ruby
|
35
|
+
class MyViewController < UIViewController
|
36
|
+
# pixate_layout { ... }
|
37
|
+
|
38
|
+
def update_label_text
|
39
|
+
subviews['title-label'] = 'An updated title'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
````
|
43
|
+
|
44
|
+
## Context and lifecycle
|
45
|
+
|
46
|
+
Be aware that inside the pixate_layout block is instance_eval'ed in the context of a proxy object, so you can't call methods on or add instance variables to your controller there. MotionPixateLayout adds 2 lifecycle hooks, `before_pixate_layout` and `after_pixate_layout` that execute in the context of your controller instance before and after the layout block, respectively.
|
47
|
+
|
48
|
+
|
49
|
+
````ruby
|
50
|
+
class MyViewController < UIViewController
|
51
|
+
pixate_layout do
|
52
|
+
@layout = true # Does not set an instance variable in controller
|
53
|
+
end
|
54
|
+
|
55
|
+
before_pixate_layout do
|
56
|
+
@layout = true # sets @layout instance variable in controller
|
57
|
+
end
|
58
|
+
|
59
|
+
after_pixate_layout do
|
60
|
+
@layout = true # sets @layout instance variable in controller
|
61
|
+
end
|
62
|
+
end
|
63
|
+
````
|
64
|
+
|
65
|
+
## Installation
|
66
|
+
|
67
|
+
If you're using Bundler, just add `gem 'motion-pixate-layout'` to your Gemfile, and `bundle install`.
|
68
|
+
|
69
|
+
Make sure you've vendored the Pixate framework and [set up motion-pixate](https://github.com/Pixate/RubyMotion-Pixate#setup).
|
70
|
+
|
71
|
+
## To-do
|
72
|
+
|
73
|
+
* Generalize to work with NUI in addition to Pixate (rename?)
|
74
|
+
* More examples
|
75
|
+
|
76
|
+
## Suggestions? Comments?
|
77
|
+
|
78
|
+
I'd love some.
|
79
|
+
|
80
|
+
## Contributions
|
81
|
+
|
82
|
+
Are welcome. Please fork and submit a pull request with some specs.
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
$:.unshift("/Library/RubyMotion/lib")
|
3
|
+
require 'motion/project'
|
4
|
+
Bundler.setup
|
5
|
+
Bundler.require
|
6
|
+
|
7
|
+
require 'motion-pixate'
|
8
|
+
|
9
|
+
Motion::Project::App.setup do |app|
|
10
|
+
app.name = 'testSuite'
|
11
|
+
app.identifier = 'com.terriblelabs.motionPixateLayout.testSuite'
|
12
|
+
|
13
|
+
app.pixate.framework = 'vendor/PXEngine.framework'
|
14
|
+
end
|
data/app/app_delegate.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
2
|
+
raise "The motion-pixate-layout gem must be required within a RubyMotion project Rakefile."
|
3
|
+
end
|
4
|
+
|
5
|
+
|
6
|
+
Motion::Project::App.setup do |app|
|
7
|
+
# scans app.files until it finds app/ (the default)
|
8
|
+
# if found, it inserts just before those files, otherwise it will insert to
|
9
|
+
# the end of the list
|
10
|
+
insert_point = 0
|
11
|
+
app.files.each_index do |index|
|
12
|
+
file = app.files[index]
|
13
|
+
if file =~ /^(?:\.\/)?app\//
|
14
|
+
# found app/, so stop looking
|
15
|
+
break
|
16
|
+
end
|
17
|
+
insert_point = index + 1
|
18
|
+
end
|
19
|
+
|
20
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'motion-pixate-layout/**/*.rb')).reverse.each do |file|
|
21
|
+
app.files.insert(insert_point, file)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module MotionPixateLayout
|
2
|
+
class Layout
|
3
|
+
attr_accessor :selector
|
4
|
+
|
5
|
+
def <<(block)
|
6
|
+
blocks << block
|
7
|
+
end
|
8
|
+
|
9
|
+
def each
|
10
|
+
blocks.each do |block|
|
11
|
+
yield block
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def after
|
16
|
+
@_after ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
def before
|
20
|
+
@_before ||= []
|
21
|
+
end
|
22
|
+
|
23
|
+
def blocks
|
24
|
+
@_blocks ||= []
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Proxy
|
29
|
+
attr_reader :view
|
30
|
+
|
31
|
+
def initialize(view)
|
32
|
+
@view = view
|
33
|
+
end
|
34
|
+
|
35
|
+
def method_missing(method_name, *args)
|
36
|
+
if Kernel.constants.include?(method_name.to_sym)
|
37
|
+
view_class = Kernel.const_get(method_name.to_s)
|
38
|
+
raise "#{view_class.name} is not a known UIView subclass" unless view_class < UIView
|
39
|
+
return subview(view_class, *args)
|
40
|
+
else
|
41
|
+
raise "#{method_name} is not defined. Should be a subclass of UIView."
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def subview(subview_class, selector, attributes = {})
|
46
|
+
selector = MotionPixateLayout::Selector.new(selector)
|
47
|
+
|
48
|
+
subview_class.new.tap do |subview|
|
49
|
+
subview.styleId = selector.style_id
|
50
|
+
subview.styleClass = selector.style_classes.join(" ")
|
51
|
+
|
52
|
+
attributes.each do |key, value|
|
53
|
+
subview.send "#{key}=", value
|
54
|
+
end
|
55
|
+
|
56
|
+
view.addSubview subview
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module MotionPixateLayout
|
2
|
+
class Selector
|
3
|
+
attr_reader :string
|
4
|
+
CLASS_PATTERN = (/\.([^#\.\s]+)/)
|
5
|
+
ID_PATTERN = (/#([^#\.\s]+)/)
|
6
|
+
|
7
|
+
def initialize(string)
|
8
|
+
@string = string
|
9
|
+
end
|
10
|
+
|
11
|
+
def style_classes
|
12
|
+
@_classes ||= string.scan(CLASS_PATTERN).flatten
|
13
|
+
end
|
14
|
+
|
15
|
+
def style_id
|
16
|
+
@_style_id ||= string.scan(ID_PATTERN).flatten.first
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class UIViewController
|
2
|
+
class << self
|
3
|
+
def pixate_layout(selector='', &block)
|
4
|
+
if block_given?
|
5
|
+
pixate_layout.selector = MotionPixateLayout::Selector.new(selector)
|
6
|
+
pixate_layout << block
|
7
|
+
else
|
8
|
+
@_pixate_layout ||= MotionPixateLayout::Layout.new
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def after_pixate_layout(&block)
|
13
|
+
pixate_layout.after << block
|
14
|
+
end
|
15
|
+
|
16
|
+
def before_pixate_layout(&block)
|
17
|
+
pixate_layout.before << block
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def pixate_layout
|
22
|
+
self.class.pixate_layout
|
23
|
+
end
|
24
|
+
|
25
|
+
def viewDidLoad
|
26
|
+
if pixate_layout.selector
|
27
|
+
view.styleId = pixate_layout.selector.style_id
|
28
|
+
view.styleClass = pixate_layout.selector.style_classes.join(' ')
|
29
|
+
end
|
30
|
+
|
31
|
+
proxy = MotionPixateLayout::Proxy.new(view)
|
32
|
+
|
33
|
+
pixate_layout.before.each do |block|
|
34
|
+
instance_eval &block
|
35
|
+
end
|
36
|
+
|
37
|
+
pixate_layout.each do |block|
|
38
|
+
proxy.instance_eval &block
|
39
|
+
end
|
40
|
+
|
41
|
+
view.updateStyles
|
42
|
+
|
43
|
+
pixate_layout.after.each do |block|
|
44
|
+
instance_eval &block
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def subviews
|
49
|
+
Hash[
|
50
|
+
view.subviews.select(&:styleId).map do |view|
|
51
|
+
[view.styleId, view]
|
52
|
+
end
|
53
|
+
].freeze
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/motion-pixate-layout/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Joe Lind"]
|
6
|
+
gem.email = ["joe@terriblelabs.com"]
|
7
|
+
gem.description = "A RubyMotion DSL to add subviews that are styled with Pixate"
|
8
|
+
gem.summary = "A RubyMotion DSL to add subviews that are styled with Pixate"
|
9
|
+
gem.homepage = 'http://github.com/terriblelabs/motion-pixate-layout'
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|lib_spec|features)/})
|
13
|
+
gem.name = "motion-pixate-layout"
|
14
|
+
gem.require_paths = ["lib"]
|
15
|
+
gem.version = MotionPixateLayout::Version
|
16
|
+
|
17
|
+
gem.add_development_dependency 'motion-pixate'
|
18
|
+
gem.add_development_dependency 'bacon'
|
19
|
+
gem.add_development_dependency 'rake'
|
20
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
describe "MotionPixateLayout::Layout" do
|
2
|
+
describe "UIViewController Extensions" do
|
3
|
+
describe "pixate_layout" do
|
4
|
+
class TestViewController < UIViewController
|
5
|
+
attr_reader :before_called
|
6
|
+
|
7
|
+
before_pixate_layout do
|
8
|
+
@before_called = true
|
9
|
+
end
|
10
|
+
|
11
|
+
pixate_layout '#view-id.view-class.view-class-2' do
|
12
|
+
UILabel '#style-id.class1.class2', text: 'Test Label'
|
13
|
+
end
|
14
|
+
|
15
|
+
after_pixate_layout do
|
16
|
+
subviews['style-id'].accessibilityLabel = 'Set after pixate layout'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
tests TestViewController
|
21
|
+
|
22
|
+
it "is added to UIViewController" do
|
23
|
+
UIViewController.should.respond_to :pixate_layout
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'sets the style id of its view from the selector' do
|
27
|
+
controller.view.styleId.should == 'view-id'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'sets the style class of its view from the selector' do
|
31
|
+
controller.view.styleClass.should == 'view-class view-class-2'
|
32
|
+
end
|
33
|
+
|
34
|
+
it "adds subviews that are specified in its block" do
|
35
|
+
controller.view.subviews.size.should == 1
|
36
|
+
end
|
37
|
+
|
38
|
+
it "assigns the styleID from subview selectors" do
|
39
|
+
controller.view.subviews.first.styleId.should == 'style-id'
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'assigns the styleClass from subview selectors' do
|
43
|
+
controller.view.subviews.first.styleClass.should == 'class1 class2'
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'exposes subviews via their styldId' do
|
47
|
+
controller.subviews['style-id'].should.be.kind_of UILabel
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'calls the before_pixate_layout blocks' do
|
51
|
+
controller.before_called.should.be.true
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'calls the after_pixate_layout blocks' do
|
55
|
+
controller.subviews['style-id'].accessibilityLabel.should == 'Set after pixate layout'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe 'Selector' do
|
2
|
+
before do
|
3
|
+
@selector = MotionPixateLayout::Selector.new('#some-id.class1.class2')
|
4
|
+
end
|
5
|
+
|
6
|
+
describe '.style_classes' do
|
7
|
+
it 'returns an array of the parsed classes from the selector' do
|
8
|
+
@selector.style_classes.should == %w[class1 class2]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.style_id' do
|
13
|
+
it "returns the id parsed from the selector" do
|
14
|
+
@selector.style_id.should == 'some-id'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: motion-pixate-layout
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joe Lind
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: motion-pixate
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bacon
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: A RubyMotion DSL to add subviews that are styled with Pixate
|
63
|
+
email:
|
64
|
+
- joe@terriblelabs.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- Gemfile
|
71
|
+
- Gemfile.lock
|
72
|
+
- LICENSE.md
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- app/app_delegate.rb
|
76
|
+
- lib/motion-pixate-layout.rb
|
77
|
+
- lib/motion-pixate-layout/layout.rb
|
78
|
+
- lib/motion-pixate-layout/selector.rb
|
79
|
+
- lib/motion-pixate-layout/version.rb
|
80
|
+
- lib/motion-pixate-layout/z_core_extensions/ui_view_controller.rb
|
81
|
+
- motion-pixate-layout.gemspec
|
82
|
+
- spec/lib/layout_spec.rb
|
83
|
+
- spec/lib/selector_spec.rb
|
84
|
+
homepage: http://github.com/terriblelabs/motion-pixate-layout
|
85
|
+
licenses: []
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 1.8.23
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: A RubyMotion DSL to add subviews that are styled with Pixate
|
108
|
+
test_files:
|
109
|
+
- spec/lib/layout_spec.rb
|
110
|
+
- spec/lib/selector_spec.rb
|
111
|
+
has_rdoc:
|