instrument 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +0 -0
- data/LICENSE +20 -0
- data/README +97 -0
- data/Rakefile +45 -0
- data/lib/instrument.rb +27 -0
- data/lib/instrument/control.rb +269 -0
- data/lib/instrument/control_builder.rb +71 -0
- data/lib/instrument/errors.rb +35 -0
- data/lib/instrument/version.rb +35 -0
- data/spec/control_templates/image_control.xhtml.haml +1 -0
- data/spec/control_templates/select_control.atom.rxml +19 -0
- data/spec/control_templates/select_control.directory.haml/explanation.txt +2 -0
- data/spec/control_templates/select_control.html.mab +5 -0
- data/spec/control_templates/select_control.json.erb +14 -0
- data/spec/control_templates/select_control.txt.bogus +2 -0
- data/spec/control_templates/select_control.xhtml.haml +4 -0
- data/spec/control_templates/select_control.xml.haml +2 -0
- data/spec/instrument/control_builder_spec.rb +37 -0
- data/spec/instrument/control_spec.rb +179 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +13 -0
- data/tasks/browse.rake +43 -0
- data/tasks/clobber.rake +2 -0
- data/tasks/gem.rake +62 -0
- data/tasks/git.rake +27 -0
- data/tasks/metrics.rake +22 -0
- data/tasks/rdoc.rake +29 -0
- data/tasks/rubyforge.rake +77 -0
- data/tasks/spec.rake +43 -0
- data/website/index.html +95 -0
- metadata +104 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
# ++
|
2
|
+
# Instrument, Copyright (c) 2008 Day Automation Systems, Inc.
|
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.
|
22
|
+
# --
|
23
|
+
|
24
|
+
require "instrument/control"
|
25
|
+
|
26
|
+
module Instrument
|
27
|
+
##
|
28
|
+
# A module which you can mixin to allow for abbreviated control
|
29
|
+
# creation.
|
30
|
+
#
|
31
|
+
# == Example
|
32
|
+
#
|
33
|
+
# include Instrument::ControlBuilder
|
34
|
+
#
|
35
|
+
# select_control(:name => "base", :selections => [
|
36
|
+
# {:label => "One", :value => "1"},
|
37
|
+
# {:label => "Two", :value => "2"},
|
38
|
+
# {:label => "Three", :value => "3"},
|
39
|
+
# {:label => "Four", :value => "4"}
|
40
|
+
# ]).to_xhtml
|
41
|
+
module ControlBuilder
|
42
|
+
##
|
43
|
+
# Prevents Kernel#select from being accidentally called.
|
44
|
+
#
|
45
|
+
# @param [Array] params the method's parameters
|
46
|
+
# @param [Proc] block the block being passed to the method
|
47
|
+
# @return [Instrument::Control] the control being created
|
48
|
+
def select(*params, &block) # :nodoc:
|
49
|
+
return self.method_missing(:select, *params, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Initializes Instrument::Control subclasses by name.
|
54
|
+
#
|
55
|
+
# @param [Symbol] method the method being called
|
56
|
+
# @param [Array] params the method's parameters
|
57
|
+
# @param [Proc] block the block being passed to the method
|
58
|
+
# @return [Instrument::Control] the control being created
|
59
|
+
# @raise NoMethodError if the method wasn't handled
|
60
|
+
def method_missing(method, *params, &block)
|
61
|
+
control_class = ::Instrument::Control.lookup(method.to_s)
|
62
|
+
if control_class != nil
|
63
|
+
return control_class.new(*params, &block)
|
64
|
+
else
|
65
|
+
raise NoMethodError,
|
66
|
+
"undefined method `#{method}' for " +
|
67
|
+
"#{self.inspect}:#{self.class.name}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# ++
|
2
|
+
# Instrument, Copyright (c) 2008 Day Automation Systems, Inc.
|
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.
|
22
|
+
# --
|
23
|
+
|
24
|
+
module Instrument
|
25
|
+
##
|
26
|
+
# Exception raised when a template cannot be found.
|
27
|
+
class ResourceNotFoundError < StandardError
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Exception raised when a template is found, but it uses an unknown
|
32
|
+
# template engine.
|
33
|
+
class InvalidTemplateEngineError < StandardError
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# ++
|
2
|
+
# Instrument, Copyright (c) 2008 Day Automation Systems, Inc.
|
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.
|
22
|
+
# --
|
23
|
+
|
24
|
+
# Used to prevent the class/module from being loaded more than once
|
25
|
+
unless defined? Instrument::VERSION
|
26
|
+
module Instrument #:nodoc:
|
27
|
+
module VERSION #:nodoc:
|
28
|
+
MAJOR = 0
|
29
|
+
MINOR = 1
|
30
|
+
TINY = 0
|
31
|
+
|
32
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
%img{:src => source, :alt => alternate_text}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "uuidtools"
|
2
|
+
require "time"
|
3
|
+
xml.instruct! :xml, :version=>"1.0"
|
4
|
+
xml.feed("xmlns" => "http://www.w3.org/2005/Atom", "xml:lang" => "en_US") do
|
5
|
+
xml.id("urn:uuid:4a11e26e-239c-11dd-adf9-001ec2186a45")
|
6
|
+
xml.title("Select Control")
|
7
|
+
xml.subtitle("Yes, this is silly, but you get the idea.")
|
8
|
+
xml.updated(Time.now.iso8601)
|
9
|
+
for selection in selections
|
10
|
+
xml.entry do
|
11
|
+
xml.id(
|
12
|
+
UUID.sha1_create(UUID_URL_NAMESPACE, "#" + selection.value).to_uri
|
13
|
+
)
|
14
|
+
xml.title(selection.label)
|
15
|
+
xml.link("#" + selection.value)
|
16
|
+
xml.updated(Time.now.iso8601)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
spec_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
2
|
+
require File.join(spec_dir, "spec_helper")
|
3
|
+
|
4
|
+
class ImageControl < Instrument::Control
|
5
|
+
def source
|
6
|
+
return self.options[:source] || self.options[:src]
|
7
|
+
end
|
8
|
+
|
9
|
+
def alternate_text
|
10
|
+
return self.options[:alternate_text] || self.options[:alt]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Verifies that Kernel#select isn't accidentally being called.
|
15
|
+
class Select < Instrument::Control
|
16
|
+
end
|
17
|
+
|
18
|
+
describe Instrument::ControlBuilder do
|
19
|
+
class ExtendedObject
|
20
|
+
include Instrument::ControlBuilder
|
21
|
+
end
|
22
|
+
|
23
|
+
before :all do
|
24
|
+
@extended_object = ExtendedObject.new
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should enable mixins to function" do
|
28
|
+
@extended_object.image_control.class.should == ImageControl
|
29
|
+
@extended_object.select.class.should == Select
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should still raise an Exception for non-existent methods" do
|
33
|
+
(lambda do
|
34
|
+
@extended_object.bogus
|
35
|
+
end).should raise_error(NoMethodError)
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
spec_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
2
|
+
require File.join(spec_dir, "spec_helper")
|
3
|
+
|
4
|
+
class SelectControl < Instrument::Control
|
5
|
+
class Option
|
6
|
+
def initialize(label, value)
|
7
|
+
@label, @value = label, value
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :label
|
11
|
+
attr_accessor :value
|
12
|
+
end
|
13
|
+
|
14
|
+
def element_id
|
15
|
+
return self.options[:id] || self.options[:name]
|
16
|
+
end
|
17
|
+
|
18
|
+
def element_name
|
19
|
+
return self.options[:name]
|
20
|
+
end
|
21
|
+
|
22
|
+
def selections
|
23
|
+
if !defined?(@selections) || @selections == nil
|
24
|
+
@selections = []
|
25
|
+
for selection in self.options[:selections]
|
26
|
+
if selection.kind_of?(Hash)
|
27
|
+
@selections << Option.new(selection[:label], selection[:value])
|
28
|
+
else
|
29
|
+
@selections << Option.new(selection, selection)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return @selections
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class SuperSelectControl < SelectControl
|
38
|
+
end
|
39
|
+
|
40
|
+
describe Instrument::Control do
|
41
|
+
it "should be able to look up subclasses by name" do
|
42
|
+
Instrument::Control.lookup("select_control").should ==
|
43
|
+
SelectControl
|
44
|
+
Instrument::Control.lookup("super_select_control").should ==
|
45
|
+
SuperSelectControl
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should have RAILS_ROOT/app/controls in the $CONTROL_PATH" do
|
49
|
+
$CONTROL_PATH.should include(File.join(RAILS_ROOT, "app/controls"))
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should not allow invalid types to be used" do
|
53
|
+
(lambda do
|
54
|
+
Instrument::Control.processor(:bogus)
|
55
|
+
end).should raise_error(ArgumentError)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should initialize subclasses via method_missing" do
|
59
|
+
Instrument::Control.new.select_control.class.should == SelectControl
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should still raise an Exception for non-existent methods" do
|
63
|
+
(lambda do
|
64
|
+
Instrument::Control.new.bogus
|
65
|
+
end).should raise_error(NoMethodError)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should raise an Exception for non-existent formats" do
|
69
|
+
(lambda do
|
70
|
+
SelectControl.new.to_bogus
|
71
|
+
end).should raise_error(Instrument::ResourceNotFoundError)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should raise an Exception if a directory is found instead of a file" do
|
75
|
+
(lambda do
|
76
|
+
SelectControl.new.to_directory
|
77
|
+
end).should raise_error(Instrument::ResourceNotFoundError)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should raise an Exception if a directory is found instead of a file" do
|
81
|
+
(lambda do
|
82
|
+
SelectControl.new.to_txt
|
83
|
+
end).should raise_error(Instrument::InvalidTemplateEngineError)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should raise an Exception if a template raises an Exception" do
|
87
|
+
(lambda do
|
88
|
+
SelectControl.new.to_xml
|
89
|
+
end).should raise_error(ZeroDivisionError)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe Instrument::Control, "when rendered as XHTML with Haml" do
|
94
|
+
before :all do
|
95
|
+
@control = SelectControl.new(:name => "base", :selections => [
|
96
|
+
"First", "Second", "Third", "Home"
|
97
|
+
])
|
98
|
+
@xhtml = @control.to_xhtml
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should have the correct id and name" do
|
102
|
+
@xhtml.should match(/<select id="base" name="base">/)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should have options for all of the given selections" do
|
106
|
+
@xhtml.should match(/<option value="First"/)
|
107
|
+
@xhtml.should match(/<option value="Second"/)
|
108
|
+
@xhtml.should match(/<option value="Third"/)
|
109
|
+
@xhtml.should match(/<option value="Home"/)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe Instrument::Control, "when rendered as HTML with Markaby" do
|
114
|
+
before :all do
|
115
|
+
@control = SelectControl.new(:name => "base", :selections => [
|
116
|
+
"First", "Second", "Third", "Home"
|
117
|
+
])
|
118
|
+
@html = @control.to_html
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should have the correct id and name" do
|
122
|
+
# Ordering of attributes is indeterminate.
|
123
|
+
@html.should match(/<select/)
|
124
|
+
@html.should match(/id="base"/)
|
125
|
+
@html.should match(/name="base"/)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should have options for all of the given selections" do
|
129
|
+
@html.should match(/<option value="First"/)
|
130
|
+
@html.should match(/<option value="Second"/)
|
131
|
+
@html.should match(/<option value="Third"/)
|
132
|
+
@html.should match(/<option value="Home"/)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe Instrument::Control, "when rendered as Atom with XML Builder" do
|
137
|
+
before :all do
|
138
|
+
@control = SelectControl.new(:name => "base", :selections => [
|
139
|
+
"First", "Second", "Third", "Home"
|
140
|
+
])
|
141
|
+
@atom = @control.to_atom
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should have the correct id and name" do
|
145
|
+
@atom.should match(/<title>Select Control<\/title>/)
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should have options for all of the given selections" do
|
149
|
+
@atom.should match(/<title>First<\/title>/)
|
150
|
+
@atom.should match(/<title>Second<\/title>/)
|
151
|
+
@atom.should match(/<title>Third<\/title>/)
|
152
|
+
@atom.should match(/<title>Home<\/title>/)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe Instrument::Control, "when rendered as JSON with Erubis" do
|
157
|
+
before :all do
|
158
|
+
@control = SelectControl.new(:name => "base", :selections => [
|
159
|
+
"First", "Second", "Third", "Home"
|
160
|
+
])
|
161
|
+
@atom = @control.to_json
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should have the correct id and name" do
|
165
|
+
@atom.should match(/"id": "base"/)
|
166
|
+
@atom.should match(/"name": "base"/)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should have options for all of the given selections" do
|
170
|
+
@atom.should match(/"label": "First"/)
|
171
|
+
@atom.should match(/"value": "First"/)
|
172
|
+
@atom.should match(/"label": "Second"/)
|
173
|
+
@atom.should match(/"value": "Second"/)
|
174
|
+
@atom.should match(/"label": "Third"/)
|
175
|
+
@atom.should match(/"value": "Third"/)
|
176
|
+
@atom.should match(/"label": "Home"/)
|
177
|
+
@atom.should match(/"value": "Home"/)
|
178
|
+
end
|
179
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# We need to test for the presence of RAILS_ROOT in the $CONTROL_PATH
|
2
|
+
if !defined?(RAILS_ROOT)
|
3
|
+
RAILS_ROOT = "somewhere/over/the/rainbow"
|
4
|
+
end
|
5
|
+
|
6
|
+
spec_dir = File.expand_path(File.dirname(__FILE__))
|
7
|
+
lib_dir = File.expand_path(File.join(spec_dir, "../lib"))
|
8
|
+
|
9
|
+
$:.unshift(lib_dir)
|
10
|
+
$:.uniq!
|
11
|
+
|
12
|
+
require "instrument"
|
13
|
+
$CONTROL_PATH.unshift(File.join(spec_dir, "control_templates"))
|
data/tasks/browse.rake
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
module Rake
|
2
|
+
def self.browse(filepath)
|
3
|
+
if RUBY_PLATFORM =~ /mswin/
|
4
|
+
system(filepath)
|
5
|
+
else
|
6
|
+
try_browsers = lambda do
|
7
|
+
result = true
|
8
|
+
if !(`which firefox 2>&1` =~ /no firefox/)
|
9
|
+
system("firefox #{filepath}")
|
10
|
+
elsif !(`which mozilla 2>&1` =~ /no mozilla/)
|
11
|
+
system("mozilla #{filepath}")
|
12
|
+
elsif !(`which netscape 2>&1` =~ /no netscape/)
|
13
|
+
system("netscape #{filepath}")
|
14
|
+
elsif !(`which links 2>&1` =~ /no links/)
|
15
|
+
system("links #{filepath}")
|
16
|
+
elsif !(`which lynx 2>&1` =~ /no lynx/)
|
17
|
+
system("lynx #{filepath}")
|
18
|
+
else
|
19
|
+
result = false
|
20
|
+
end
|
21
|
+
result
|
22
|
+
end
|
23
|
+
opened = false
|
24
|
+
if RUBY_PLATFORM =~ /darwin/
|
25
|
+
opened = true
|
26
|
+
system("open #{filepath}")
|
27
|
+
elsif !(`which gnome-open 2>&1` =~ /no gnome-open/)
|
28
|
+
success =
|
29
|
+
!(`gnome-open #{filepath} 2>&1` =~ /There is no default action/)
|
30
|
+
if !success
|
31
|
+
opened = try_browsers.call()
|
32
|
+
else
|
33
|
+
opened = true
|
34
|
+
end
|
35
|
+
else
|
36
|
+
opened = try_browsers.call()
|
37
|
+
end
|
38
|
+
if !opened
|
39
|
+
puts "Don't know how to browse to location."
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|