everyday-menu 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +23 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +24 -0
- data/README.md +75 -0
- data/Rakefile +24 -0
- data/everyday-menu.gemspec +22 -0
- data/examples/basic_main_menu/app_delegate.rb +24 -0
- data/examples/basic_main_menu/main_menu.rb +20 -0
- data/lib/everyday-menu.rb +9 -0
- data/lib/everyday-menu/menu.rb +152 -0
- data/lib/everyday-menu/menu_builder.rb +70 -0
- data/lib/everyday-menu/menu_item.rb +123 -0
- data/lib/everyday-menu/version.rb +3 -0
- data/spec/menu_builder_spec.rb +105 -0
- data/spec/menu_item_spec.rb +38 -0
- data/spec/menu_spec.rb +70 -0
- metadata +24 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8629e47d2c83c578b36c97f19929b19510a2f109
|
4
|
+
data.tar.gz: 33d50f3c20d86ade4efb059ca5c540ec8fc3fd5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d52d5545f858e73378246066a05eb524fab4363eacc03cba1876d80e9c5b6f58a86342c2736884b9313a85d0a3ce49645da321bb7df7f1a45c3ae52199e8e2e3
|
7
|
+
data.tar.gz: 4cfac1436396e77297c61d1745eab23bbb455baa64b184146fa73310b1c599de978887be0ed59f62ab10a7a04e05a8d5f9103ddc213440474019bba0aed4cdcc
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
build
|
19
|
+
vendor
|
20
|
+
|
21
|
+
/.idea/
|
22
|
+
|
23
|
+
/projectFilesBackup/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Here is the copyright from drink-menu, which I based a lot of my code on:
|
2
|
+
|
3
|
+
Copyright (c) 2013 Joe Fiorini
|
4
|
+
|
5
|
+
MIT License
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
8
|
+
a copy of this software and associated documentation files (the
|
9
|
+
"Software"), to deal in the Software without restriction, including
|
10
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
+
permit persons to whom the Software is furnished to do so, subject to
|
13
|
+
the following conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# EverydayMenu
|
2
|
+
|
3
|
+
## Credit
|
4
|
+
Please note that this gem is strongly based off of Joe Fiorini's `drink-menu` gem (with a little code copy-paste and lots of test and readme copy-paste), which I couldn't get to work for me.
|
5
|
+
|
6
|
+
You can find his gem at <https://github.com/joefiorini/drink-menu>. He doesn't get all of the credit, but he gets a lot of it.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'everyday-menu'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install everyday-menu
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
Everyday Menu separates menu layout from menu definition. Menu definition looks like:
|
25
|
+
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
class MainMenu
|
29
|
+
extend EverydayMenu::MenuBuilder
|
30
|
+
|
31
|
+
menuItem :create_site, 'Create Site'
|
32
|
+
menuItem :export, 'Export to Folder...'
|
33
|
+
menuItem :import, 'Import Folder as Site...'
|
34
|
+
menuItem :force_rebuild, 'Force Rebuild'
|
35
|
+
menuItem :about, 'About Staticly'
|
36
|
+
menuItem :quit, 'Quit', key_equivalent: 'q'
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
and then layout is as simple as:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
|
44
|
+
class MainMenu
|
45
|
+
extend EverydayMenu::MenuBuilder
|
46
|
+
|
47
|
+
mainMenu :main_menu, 'Main Menu' do
|
48
|
+
create_site
|
49
|
+
___
|
50
|
+
export
|
51
|
+
import
|
52
|
+
force_rebuild
|
53
|
+
___
|
54
|
+
about
|
55
|
+
quit
|
56
|
+
end
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
## Running the Examples
|
61
|
+
|
62
|
+
To run our example apps:
|
63
|
+
|
64
|
+
1. Clone this repo
|
65
|
+
2. From within your clone's root, run `platform=osx example=basic_main_menu rake`
|
66
|
+
|
67
|
+
You can replace the value of `example` with any folder under the `examples` directory to run that example.
|
68
|
+
|
69
|
+
## Contributing
|
70
|
+
|
71
|
+
1. Fork it
|
72
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
73
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
74
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
75
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.unshift('/Library/RubyMotion/lib')
|
2
|
+
|
3
|
+
if ENV['platform'] == 'osx'
|
4
|
+
require 'motion/project/template/osx'
|
5
|
+
else
|
6
|
+
raise 'The everyday-menu gem must be used within an OSX project.'
|
7
|
+
end
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'bundler'
|
11
|
+
Bundler.require
|
12
|
+
rescue LoadError
|
13
|
+
# ignored
|
14
|
+
end
|
15
|
+
|
16
|
+
Motion::Project::App.setup do |app|
|
17
|
+
app.name = 'everyday-menu'
|
18
|
+
app.identifier = 'us.myepg.everyday-menu'
|
19
|
+
app.specs_dir = 'spec/'
|
20
|
+
|
21
|
+
if ENV['example']
|
22
|
+
app.files << Dir["examples/#{ENV['example']}/**/*.rb"]
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'everyday-menu/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'everyday-menu'
|
8
|
+
spec.version = EverydayMenu::VERSION
|
9
|
+
spec.authors = ['Eric Henderson']
|
10
|
+
spec.email = ['henderea@gmail.com']
|
11
|
+
spec.description = %q{An easy way to define menu items and visually lay out menus for your OSX apps. Based strongly on the drink-menu gem that I couldn't get to work for me.}
|
12
|
+
spec.summary = %q{A more ruby way to create OS X menus in RubyMotion}
|
13
|
+
spec.homepage = 'https://github.com/henderea/everyday-menu'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
21
|
+
spec.add_development_dependency 'rake', '~> 10.0.0'
|
22
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class AppDelegate
|
2
|
+
|
3
|
+
def applicationDidFinishLaunching(notification)
|
4
|
+
MainMenu.build!
|
5
|
+
|
6
|
+
MainMenu[:app].subscribe :quit do |_|
|
7
|
+
NSApp.terminate(self)
|
8
|
+
end
|
9
|
+
|
10
|
+
MainMenu[:file].subscribe :new do |_|
|
11
|
+
puts 'new'
|
12
|
+
end
|
13
|
+
|
14
|
+
MainMenu[:file].subscribe :close do |_|
|
15
|
+
puts 'close'
|
16
|
+
end
|
17
|
+
|
18
|
+
MainMenu[:file].subscribe :open do |_|
|
19
|
+
puts 'open'
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class MainMenu
|
2
|
+
extend EverydayMenu::MenuBuilder
|
3
|
+
|
4
|
+
menuItem :quit, 'Quit', key_equivalent: 'q'
|
5
|
+
menuItem :open, 'Open', key_equivalent: 'o'
|
6
|
+
menuItem :new, 'New'
|
7
|
+
|
8
|
+
menuItem :close, 'Close', key_equivalent: 'w'
|
9
|
+
|
10
|
+
mainMenu :app, 'Blah' do
|
11
|
+
quit
|
12
|
+
end
|
13
|
+
|
14
|
+
mainMenu :file, 'File' do
|
15
|
+
new
|
16
|
+
open
|
17
|
+
___
|
18
|
+
close
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
2
|
+
raise 'The everyday-menu gem must be required within a RubyMotion project Rakefile.'
|
3
|
+
end
|
4
|
+
|
5
|
+
Motion::Project::App.setup do |app|
|
6
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'everyday-menu/**/*.rb')).each do |file|
|
7
|
+
app.files.unshift(file)
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module EverydayMenu
|
2
|
+
class Menu
|
3
|
+
attr_reader :needsMenuItem
|
4
|
+
|
5
|
+
def self.create(label, title, options = {}, &block)
|
6
|
+
new(label, &block).tap { |menu|
|
7
|
+
menu[:label] = label
|
8
|
+
menu[:title] = title
|
9
|
+
options.each { |option| menu[option[0]] = option[1] }
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(label, &block)
|
14
|
+
@label = label
|
15
|
+
@builder = block
|
16
|
+
@menu = NSMenu.alloc.init
|
17
|
+
@menuItems = MenuItemList.new(@menu)
|
18
|
+
@needsMenuItem = false
|
19
|
+
end
|
20
|
+
|
21
|
+
def menuItemFromMenu!
|
22
|
+
@mainMenuItem ||= MenuItem.create(self[:label], self[:title], submenu: self)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
alias :menu_item_for_menu! :menuItemFromMenu!
|
27
|
+
|
28
|
+
def menuItem
|
29
|
+
@mainMenuItem.item
|
30
|
+
end
|
31
|
+
|
32
|
+
alias :menu_item :menuItem
|
33
|
+
|
34
|
+
def subscribe(label, &block)
|
35
|
+
self.items[label].subscribe(&block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def <<(item)
|
39
|
+
@menuItems << item
|
40
|
+
end
|
41
|
+
|
42
|
+
def has(key)
|
43
|
+
name = key_to_name(key, 'has')
|
44
|
+
begin
|
45
|
+
self.send(name)
|
46
|
+
rescue NoMethodError
|
47
|
+
@menu.send(name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def is(key)
|
52
|
+
name = key_to_name(key, 'is')
|
53
|
+
begin
|
54
|
+
self.send(name)
|
55
|
+
rescue NoMethodError
|
56
|
+
@menu.send(name)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def [](key)
|
61
|
+
name = key_to_name(key)
|
62
|
+
begin
|
63
|
+
self.send(name)
|
64
|
+
rescue NoMethodError
|
65
|
+
@menu.send(name)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def []=(key, value)
|
70
|
+
name = key_to_name(key, 'set')
|
71
|
+
begin
|
72
|
+
self.send(name, value)
|
73
|
+
rescue NoMethodError
|
74
|
+
@menu.send(name, value)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def key_to_name(key, prefix = nil)
|
79
|
+
rval = key.to_s.gsub(/_(\w)/) { |_| $1.upcase }
|
80
|
+
prefix.nil? ? rval : "#{prefix}#{rval[0].upcase}#{rval[1..-1]}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def label
|
84
|
+
@label ||= nil
|
85
|
+
end
|
86
|
+
|
87
|
+
def setLabel(label)
|
88
|
+
@label = label
|
89
|
+
end
|
90
|
+
|
91
|
+
alias :label= :setLabel
|
92
|
+
|
93
|
+
def items
|
94
|
+
@menuItems
|
95
|
+
end
|
96
|
+
|
97
|
+
def menu
|
98
|
+
@menu
|
99
|
+
end
|
100
|
+
|
101
|
+
def builder
|
102
|
+
@builder
|
103
|
+
end
|
104
|
+
|
105
|
+
def isMainMenu
|
106
|
+
@needsMenuItem
|
107
|
+
end
|
108
|
+
|
109
|
+
alias :mainMenu :isMainMenu
|
110
|
+
alias :main_menu? :isMainMenu
|
111
|
+
|
112
|
+
def setMainMenu(value)
|
113
|
+
@needsMenuItem = value
|
114
|
+
end
|
115
|
+
|
116
|
+
alias :main_menu= :setMainMenu
|
117
|
+
end
|
118
|
+
|
119
|
+
class MenuItemList
|
120
|
+
def initialize(menu)
|
121
|
+
@menuItems = {}
|
122
|
+
@menu = menu
|
123
|
+
end
|
124
|
+
|
125
|
+
def <<(item)
|
126
|
+
previousItemTag = @menuItems.keys.last || 0
|
127
|
+
item[:tag] = previousItemTag + 1
|
128
|
+
@menuItems[item[:tag]] = item
|
129
|
+
@menu.addItem item.menuItem
|
130
|
+
end
|
131
|
+
|
132
|
+
def [](labelOrTag)
|
133
|
+
(labelOrTag.is_a? Fixnum) ? @menuItems[labelOrTag] : @menuItems.values.find { |item| item.label == labelOrTag }
|
134
|
+
end
|
135
|
+
|
136
|
+
def selectItem(label)
|
137
|
+
item = self[label]
|
138
|
+
item.execute
|
139
|
+
end
|
140
|
+
|
141
|
+
alias :select_item :selectItem
|
142
|
+
|
143
|
+
def selectItemByMember(member)
|
144
|
+
item = @menuItems.values.find do |i|
|
145
|
+
i[:represented_object] == member
|
146
|
+
end
|
147
|
+
item.execute
|
148
|
+
end
|
149
|
+
|
150
|
+
alias :select_item_by_member :selectItemByMember
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module EverydayMenu
|
2
|
+
module MenuBuilder
|
3
|
+
class Context < BasicObject
|
4
|
+
def initialize(menu, menuItems={})
|
5
|
+
@menu = menu
|
6
|
+
@menuItems = menuItems
|
7
|
+
end
|
8
|
+
|
9
|
+
def ___
|
10
|
+
@menu << MenuItem.separator
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(meth, *args)
|
14
|
+
if @menuItems.key?(meth)
|
15
|
+
@menu << @menuItems[meth]
|
16
|
+
else
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def <<(item)
|
23
|
+
@menuItems ||= {}
|
24
|
+
@menuItems[item.label] = item
|
25
|
+
end
|
26
|
+
|
27
|
+
def menuItem(label, title, options = {})
|
28
|
+
options[:submenu] = @menus[options[:submenu]] if options.has_key?(:submenu)
|
29
|
+
self << MenuItem.create(label, title, options)
|
30
|
+
end
|
31
|
+
|
32
|
+
alias :menu_item :menuItem
|
33
|
+
|
34
|
+
def mainMenu(label, title, options = {}, &block)
|
35
|
+
options[:main_menu] = true
|
36
|
+
@menus ||= {}
|
37
|
+
@menus[label] = Menu.create(label, title, options, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
alias :main_menu :mainMenu
|
41
|
+
|
42
|
+
def menu(label, title, options = {}, &block)
|
43
|
+
options[:main_menu] = false
|
44
|
+
@menus ||= {}
|
45
|
+
@menus[label] = Menu.create(label, title, options, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def [](label)
|
49
|
+
@menus[label]
|
50
|
+
end
|
51
|
+
|
52
|
+
def build!
|
53
|
+
@menus.values.each do |menu|
|
54
|
+
context = Context.new(menu, @menuItems.dup)
|
55
|
+
context.instance_eval(&menu.builder) if menu.builder
|
56
|
+
if menu.is :main_menu
|
57
|
+
@mainMenu ||= NSMenu.new
|
58
|
+
@mainMenu.addItem menu.menuItemFromMenu!.menuItem
|
59
|
+
end
|
60
|
+
end
|
61
|
+
setupMainMenu if @mainMenu
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def setupMainMenu
|
67
|
+
NSApp.mainMenu = @mainMenu
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module EverydayMenu
|
2
|
+
class MenuItem
|
3
|
+
def self.create(label, title, options = {})
|
4
|
+
new.tap { |item|
|
5
|
+
item[:label] = label
|
6
|
+
item[:title] = title
|
7
|
+
options.each { |option| item[option[0]] = option[1] }
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.separator
|
12
|
+
@@separatorId ||= 0
|
13
|
+
@@separatorId += 1
|
14
|
+
label = :"separator#{@@separatorId}"
|
15
|
+
new(NSMenuItem.separatorItem).tap do |item|
|
16
|
+
item.label = label
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.separatorItem
|
21
|
+
self.separator
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(menuItem=nil)
|
25
|
+
@menuItem = menuItem || NSMenuItem.alloc.init
|
26
|
+
end
|
27
|
+
|
28
|
+
def has(key)
|
29
|
+
name = key_to_name(key, 'has')
|
30
|
+
begin
|
31
|
+
self.send(name)
|
32
|
+
rescue NoMethodError
|
33
|
+
@menuItem.send(name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def is(key)
|
38
|
+
name = key_to_name(key, 'is')
|
39
|
+
begin
|
40
|
+
self.send(name)
|
41
|
+
rescue NoMethodError
|
42
|
+
@menuItem.send(name)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def [](key)
|
47
|
+
name = key_to_name(key)
|
48
|
+
begin
|
49
|
+
self.send(name)
|
50
|
+
rescue NoMethodError
|
51
|
+
@menuItem.send(name)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def []=(key, value)
|
56
|
+
name = key_to_name(key, 'set')
|
57
|
+
begin
|
58
|
+
self.send(name, value)
|
59
|
+
rescue NoMethodError
|
60
|
+
@menuItem.send(name, value)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def key_to_name(key, prefix = nil)
|
65
|
+
rval = key.to_s.gsub(/_(\w)/) { |_| $1.upcase }
|
66
|
+
prefix.nil? ? rval : "#{prefix}#{rval[0].upcase}#{rval[1..-1]}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def setSubmenu(menu)
|
70
|
+
@menuItem.submenu = menu.menu
|
71
|
+
end
|
72
|
+
|
73
|
+
def menuItem
|
74
|
+
@menuItem
|
75
|
+
end
|
76
|
+
|
77
|
+
alias :menu_item :menuItem
|
78
|
+
alias :item :menuItem
|
79
|
+
|
80
|
+
def label
|
81
|
+
@label ||= nil
|
82
|
+
end
|
83
|
+
|
84
|
+
def setLabel(label)
|
85
|
+
@label = label
|
86
|
+
end
|
87
|
+
|
88
|
+
alias :label= :setLabel
|
89
|
+
|
90
|
+
def tag
|
91
|
+
@menuItem.tag
|
92
|
+
end
|
93
|
+
|
94
|
+
def setTag(tag)
|
95
|
+
@menuItem.tag = tag
|
96
|
+
end
|
97
|
+
|
98
|
+
alias :tag= :setTag
|
99
|
+
|
100
|
+
def subscribe(&block)
|
101
|
+
@menuItem.subscribe(&block)
|
102
|
+
end
|
103
|
+
|
104
|
+
def execute
|
105
|
+
@menuItem.runBlock(self)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class NSMenuItem
|
111
|
+
def subscribe(&block)
|
112
|
+
@blocks ||= []
|
113
|
+
@blocks << block
|
114
|
+
return if (self.target = self && self.action == :'runBlocks:')
|
115
|
+
@original_target = self.target
|
116
|
+
self.target = self
|
117
|
+
self.action = :'runBlock:'
|
118
|
+
end
|
119
|
+
|
120
|
+
def runBlock(sender)
|
121
|
+
@blocks.each { |block| block.call(sender) } unless @blocks.nil?
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
class TestMenu;
|
2
|
+
extend EverydayMenu::MenuBuilder;
|
3
|
+
end
|
4
|
+
class TestMenu2;
|
5
|
+
include EverydayMenu::MenuBuilder;
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'sugar for creating menus' do
|
9
|
+
|
10
|
+
it 'supports defining menu items' do
|
11
|
+
menuItem = TestMenu.menuItem :create_site, 'Create Site'
|
12
|
+
menuItem[:label].should.equal :create_site
|
13
|
+
menuItem[:title].should.equal 'Create Site'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'builds gives access to menu instance' do
|
17
|
+
TestMenu.menuItem :create_site, 'Create Site'
|
18
|
+
TestMenu.menu :main_menu, 'Main'
|
19
|
+
menu = TestMenu[:main_menu]
|
20
|
+
menu.should.be.an.instance_of EverydayMenu::Menu
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'allows creating a top-level menu' do
|
24
|
+
menu = TestMenu.menu :main_menu, 'Blah'
|
25
|
+
menu.menu.should.be.an.instance_of NSMenu
|
26
|
+
menu[:title].should.equal 'Blah'
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'evaluates menu\'s block to add items to menu' do
|
30
|
+
builder = TestMenu2.new
|
31
|
+
item1 = builder.menuItem :test_item1, 'Blah'
|
32
|
+
item2 = builder.menuItem :test_item2, 'Blah'
|
33
|
+
|
34
|
+
builder.menu :main_menu, 'Main' do
|
35
|
+
test_item1
|
36
|
+
___
|
37
|
+
test_item2
|
38
|
+
end
|
39
|
+
|
40
|
+
builder.build!
|
41
|
+
|
42
|
+
builder[:main_menu][:test_item1].should.equal item1
|
43
|
+
builder[:main_menu][:test_item2].should.equal item2
|
44
|
+
|
45
|
+
builder[:main_menu][2].is(:separator_item).should.be.true
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'supports generating an NSApp\'s mainMenu items' do
|
49
|
+
builder = TestMenu2.new
|
50
|
+
testItem1 = builder.menuItem :test_item1, 'Blah 1'
|
51
|
+
testItem2 = builder.menuItem :test_item2, 'Blah 2'
|
52
|
+
|
53
|
+
menu1 = builder.mainMenu :menu1, 'Menu 1' do
|
54
|
+
test_item1
|
55
|
+
end
|
56
|
+
|
57
|
+
menu2 = builder.mainMenu :menu2, 'Menu 2' do
|
58
|
+
test_item2
|
59
|
+
end
|
60
|
+
|
61
|
+
builder.build!
|
62
|
+
|
63
|
+
mainMenu = NSApp.mainMenu
|
64
|
+
|
65
|
+
menuItem = mainMenu.itemArray[0]
|
66
|
+
puts "menu1 title: #{menu1.title.inspect}"
|
67
|
+
puts "menuItem title: #{menuItem.title.inspect}"
|
68
|
+
menuItem.title.should.equal menu1[:title]
|
69
|
+
menuItem.submenu.title.should.equal menu1[:title]
|
70
|
+
menuItem.submenu.itemArray[0].title.should.equal('Blah 1')
|
71
|
+
|
72
|
+
menuItem = mainMenu.itemArray[1]
|
73
|
+
menuItem.title.should.equal menu2[:title]
|
74
|
+
menuItem.submenu.title.should.equal menu2[:title]
|
75
|
+
menuItem.submenu.itemArray[0].title.should.equal('Blah 2')
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'builder\'s context class' do
|
79
|
+
|
80
|
+
Context = EverydayMenu::MenuBuilder::Context
|
81
|
+
|
82
|
+
it 'adds item to menu by calling method named after item\'s label' do
|
83
|
+
menu = EverydayMenu::Menu.create :test, 'Test'
|
84
|
+
item = EverydayMenu::MenuItem.create :test_item, 'Blah'
|
85
|
+
context = Context.new(menu, { test_item: item })
|
86
|
+
|
87
|
+
menu[:test_item].should.be.nil
|
88
|
+
|
89
|
+
context.test_item
|
90
|
+
|
91
|
+
menu[:test_item].should.equal item
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'creates separators from ___' do
|
95
|
+
menu = EverydayMenu::Menu.create :test, 'Test'
|
96
|
+
|
97
|
+
menu[1].should.be.nil
|
98
|
+
|
99
|
+
Context.new(menu).__send__ :'___'
|
100
|
+
|
101
|
+
menu[1].is[:separator_item].should.be.true
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
describe 'creating menu items' do
|
2
|
+
|
3
|
+
it 'keeps the title and label' do
|
4
|
+
m = EverydayMenu::MenuItem.create :create_site, 'Create Site'
|
5
|
+
m[:label].should.equal :create_site
|
6
|
+
m[:title].should.equal 'Create Site'
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'has an instance of NSMenuItem' do
|
10
|
+
m = EverydayMenu::MenuItem.create :create_site, 'Create Site'
|
11
|
+
m.menuItem.should.be.a.instance_of NSMenuItem
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'allows extra options to create method' do
|
15
|
+
m = EverydayMenu::MenuItem.create :create_site, 'Create Site', enabled: false, tag: 1, state: NSOnState
|
16
|
+
m.menuItem.title.should.equal m.title
|
17
|
+
m.menuItem.isEnabled.should.equal m.isEnabled
|
18
|
+
m.menuItem.tag.should.equal m.tag
|
19
|
+
m.menuItem.image.should.equal m.image
|
20
|
+
m.menuItem.state.should.equal m.state
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'allows creating separator items' do
|
24
|
+
item = EverydayMenu::MenuItem.separatorItem
|
25
|
+
item.is(:separator_item).should.be.true
|
26
|
+
end
|
27
|
+
|
28
|
+
def separator_id(item)
|
29
|
+
item.label[/\d+$/].to_i
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'generates unique label for separators' do
|
33
|
+
item1 = EverydayMenu::MenuItem.separatorItem
|
34
|
+
item2 = EverydayMenu::MenuItem.separatorItem
|
35
|
+
separator_id(item2).should.equal separator_id(item1) + 1
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/spec/menu_spec.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
describe 'creating menus' do
|
2
|
+
|
3
|
+
|
4
|
+
it 'creates an NSMenu instance' do
|
5
|
+
menu = EverydayMenu::Menu.create :test, 'Test'
|
6
|
+
menu.menu.should.be.an.instance_of NSMenu
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'sets title on NSMenu instance' do
|
10
|
+
menu = EverydayMenu::Menu.create :test_menu, 'title'
|
11
|
+
menu[:title].should.equal 'title'
|
12
|
+
menu.menu.title.should.equal menu[:title]
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'automatically adds NSMenuItem instance to NSMenu' do
|
16
|
+
menu = EverydayMenu::Menu.create :test, 'Test'
|
17
|
+
item = EverydayMenu::MenuItem.create :test_item, 'Blah'
|
18
|
+
menu << item
|
19
|
+
|
20
|
+
menu[:item_array].should.include item.menuItem
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'sets a unique tag on each menu item as it is added' do
|
25
|
+
menu = EverydayMenu::Menu.create :test, 'Test'
|
26
|
+
item1 = EverydayMenu::MenuItem.create :test_item1, 'Blah'
|
27
|
+
item2 = EverydayMenu::MenuItem.create :test_item2, 'Diddy'
|
28
|
+
|
29
|
+
menu << item1
|
30
|
+
menu << item2
|
31
|
+
|
32
|
+
item1.menuItem.tag.should.equal 1
|
33
|
+
item2.menuItem.tag.should.equal 2
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'allows looking up menu items by label' do
|
38
|
+
menu = EverydayMenu::Menu.create :test, 'Test'
|
39
|
+
item = EverydayMenu::MenuItem.create :test_item, 'Blah'
|
40
|
+
|
41
|
+
menu << item
|
42
|
+
|
43
|
+
menu[item.label].should.equal item
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'allows selecting an item by its label' do
|
47
|
+
handled = false
|
48
|
+
menu = EverydayMenu::Menu.create :test, 'Test'
|
49
|
+
item = EverydayMenu::MenuItem.create :test_item, 'Blah'
|
50
|
+
|
51
|
+
menu << item
|
52
|
+
|
53
|
+
menu.subscribe :test_item do |_|
|
54
|
+
handled = true
|
55
|
+
end
|
56
|
+
|
57
|
+
menu.selectItem :test_item
|
58
|
+
|
59
|
+
handled.should.be.true
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'allows looking up menu items by tag' do
|
63
|
+
menu = EverydayMenu::Menu.create :test, 'Test'
|
64
|
+
item = EverydayMenu::MenuItem.create :test_item, 'Blah'
|
65
|
+
|
66
|
+
menu << item
|
67
|
+
|
68
|
+
menu[1].should.equal item
|
69
|
+
end
|
70
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: everyday-menu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Henderson
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 10.0.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 10.0.0
|
41
41
|
description: An easy way to define menu items and visually lay out menus for your
|
42
42
|
OSX apps. Based strongly on the drink-menu gem that I couldn't get to work for me.
|
43
43
|
email:
|
@@ -45,7 +45,23 @@ email:
|
|
45
45
|
executables: []
|
46
46
|
extensions: []
|
47
47
|
extra_rdoc_files: []
|
48
|
-
files:
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- everyday-menu.gemspec
|
55
|
+
- examples/basic_main_menu/app_delegate.rb
|
56
|
+
- examples/basic_main_menu/main_menu.rb
|
57
|
+
- lib/everyday-menu.rb
|
58
|
+
- lib/everyday-menu/menu.rb
|
59
|
+
- lib/everyday-menu/menu_builder.rb
|
60
|
+
- lib/everyday-menu/menu_item.rb
|
61
|
+
- lib/everyday-menu/version.rb
|
62
|
+
- spec/menu_builder_spec.rb
|
63
|
+
- spec/menu_item_spec.rb
|
64
|
+
- spec/menu_spec.rb
|
49
65
|
homepage: https://github.com/henderea/everyday-menu
|
50
66
|
licenses:
|
51
67
|
- MIT
|
@@ -70,5 +86,8 @@ rubygems_version: 2.2.0
|
|
70
86
|
signing_key:
|
71
87
|
specification_version: 4
|
72
88
|
summary: A more ruby way to create OS X menus in RubyMotion
|
73
|
-
test_files:
|
89
|
+
test_files:
|
90
|
+
- spec/menu_builder_spec.rb
|
91
|
+
- spec/menu_item_spec.rb
|
92
|
+
- spec/menu_spec.rb
|
74
93
|
has_rdoc:
|