sapphire 0.2.2 → 0.3.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/bin/sapphire ADDED
@@ -0,0 +1,12 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
2
+
3
+ require 'sapphire'
4
+
5
+ include Sapphire::Sapphire
6
+
7
+ ARGV.each do |arg|
8
+ require arg
9
+ Runner.instance.last_scenario.execute 1
10
+ end
11
+
12
+ ConsoleReporter.new().OutputResults
data/lib/sapphire.rb CHANGED
@@ -1,4 +1,3 @@
1
- require "test/unit"
2
1
  require "rubygems"
3
2
  require "rspec"
4
3
  require 'yaml'
@@ -6,14 +5,18 @@ require 'selenium-webdriver'
6
5
  require 'delegate'
7
6
  require 'Forwardable'
8
7
  require 'win32ole'
8
+ require 'win32console'
9
9
  require 'json'
10
+ require 'colorize'
10
11
 
11
12
  require File.expand_path(File.dirname(__FILE__) +'/sapphire/Strategies/Strategy.rb', __FILE__)
13
+ require File.expand_path(File.dirname(__FILE__) +'/sapphire/Testing/Reporter.rb', __FILE__)
12
14
  Dir[File.dirname(__FILE__) + '/sapphire/Testing/*.rb'].each {|file| require file }
13
15
  Dir[File.dirname(__FILE__) + '/sapphire/Configuration/*.rb'].each {|file| require file }
14
16
  Dir[File.dirname(__FILE__) + '/sapphire/WebAbstractions/Controls/Base/*.rb'].each {|file| require file }
15
17
  Dir[File.dirname(__FILE__) + '/sapphire/WebAbstractions/Controls/*.rb'].each {|file| require file }
16
18
  Dir[File.dirname(__FILE__) + '/sapphire/DataAbstractions/*.rb'].each {|file| require file }
19
+ Dir[File.dirname(__FILE__) + '/sapphire/JobAbstractions/*.rb'].each {|file| require file }
17
20
  Dir[File.dirname(__FILE__) + '/sapphire/Strategies/*.rb'].each {|file| require file }
18
21
  Dir[File.dirname(__FILE__) + '/sapphire/DSL/Browser/*.rb'].each {|file| require file }
19
22
  Dir[File.dirname(__FILE__) + '/sapphire/DSL/Configuration/*.rb'].each {|file| require file }
@@ -32,6 +35,7 @@ module Sapphire
32
35
  include Configuration::AttrMethods
33
36
  include Configuration
34
37
  include DataAbstractions
38
+ include JobAbstractions
35
39
  include WebAbstractions
36
40
  include Testing
37
41
  end
@@ -0,0 +1,10 @@
1
+ module Sapphire
2
+ module DSL
3
+ module Browser
4
+ def Accept(browser)
5
+ x = browser.new
6
+ x.Accept
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ module Sapphire
2
+ module DSL
3
+ module Browser
4
+ class AlertBox
5
+ def Accept
6
+ alert = $browser.switch_to.alert
7
+ alert.accept()
8
+ $browser.switch_to.window($browser.window_handles[0])
9
+ end
10
+
11
+ def Set(text)
12
+ alert = $browser.switch_to.alert
13
+ alert.send_keys(text)
14
+ alert.accept()
15
+ $browser.switch_to.window($browser.window_handles[0])
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -2,8 +2,14 @@ module Sapphire
2
2
  module DSL
3
3
  module Browser
4
4
  def Set(hash)
5
- ExecuteHashAgainstControl(hash, @page) do |control, arg|
6
- control.Set arg
5
+ if(hash.keys.first == AlertBox)
6
+ text = hash[item.keys.first]
7
+ klass = hash.keys.first.new
8
+ klass.Set text
9
+ else
10
+ ExecuteHashAgainstControl(hash, @page) do |control, arg|
11
+ control.Set arg
12
+ end
7
13
  end
8
14
  end
9
15
  end
@@ -18,6 +18,7 @@ class And
18
18
  end
19
19
 
20
20
  def AddResult(result)
21
+ result.item = self
21
22
  @results << result
22
23
  self.parent.results.last.AddChild(result)
23
24
  end
@@ -16,6 +16,7 @@ class Background
16
16
  end
17
17
 
18
18
  def AddResult(result)
19
+ result.item = self
19
20
  @results << result
20
21
  self.parent.result.AddChild(result)
21
22
  end
@@ -50,8 +50,8 @@ module Sapphire
50
50
 
51
51
  def Scenario(text, &block)
52
52
  Runner.instance.add_scenario(Scenario.new(text, &block))
53
- #Runner.instance.last_scenario.block.call
54
- Runner.instance.last_scenario.execute 1
53
+ Runner.instance.last_scenario.block.call
54
+ #Runner.instance.last_scenario.execute 1
55
55
  end
56
56
  end
57
57
  end
@@ -26,7 +26,9 @@ class Finally
26
26
  end
27
27
 
28
28
  def AddResult(result)
29
+ result.item = self
29
30
  @results << result
31
+ self.parent.AddResult(result)
30
32
  end
31
33
 
32
34
  end
@@ -45,11 +45,12 @@ class Given
45
45
  if(self.value.is_a? Pending)
46
46
  self.and << And.new(self, Pending.new(pre + text), &block)
47
47
  else
48
- self.and << And.new(self, text, &block)
48
+ self.and << And.new(self, pre + text, &block)
49
49
  end
50
50
  end
51
51
 
52
52
  def AddResult(result)
53
+ result.item = self
53
54
  @results << result
54
55
  self.parent.result.AddChild(result)
55
56
  end
@@ -2,7 +2,7 @@ module Sapphire
2
2
  module DSL
3
3
  module Scenarios
4
4
  class Scenario
5
- include Sapphire::Testing::RSpecRunner
5
+ include Sapphire::Testing::TestRunnerAdapter
6
6
 
7
7
  attr_reader :block
8
8
  attr_reader :value
@@ -27,6 +27,7 @@ class Then
27
27
  end
28
28
 
29
29
  def AddResult(result)
30
+ result.item = self
30
31
  @results << result
31
32
  self.parent.results.last.AddChild(result)
32
33
  end
@@ -40,6 +40,7 @@ class When
40
40
  end
41
41
 
42
42
  def AddResult(result)
43
+ result.item = self
43
44
  @results << result
44
45
  self.parent.results.last.AddChild(result)
45
46
  end
@@ -5,6 +5,9 @@ module Sapphire
5
5
  def Handle(item)
6
6
  x = AppConfig.Current.SpecsPath || ""
7
7
  require File.expand_path(x + item, __FILE__)
8
+ $stdout.puts item + ": "
9
+ Runner.instance.last_scenario.execute 1
10
+ $stdout.puts ""
8
11
  end
9
12
  end
10
13
  end
@@ -4,7 +4,12 @@ module Sapphire
4
4
  class PathHandler
5
5
  def Handle(item)
6
6
  x = AppConfig.Current.SpecsPath || ""
7
- Dir[x + item + '*.rb'].each do |file| require file end
7
+ Dir[x + item + '*.rb'].each do |file|
8
+ require file
9
+ $stdout.puts file + ": "
10
+ Runner.instance.last_scenario.execute 1
11
+ $stdout.puts ""
12
+ end
8
13
  end
9
14
  end
10
15
  end
@@ -2,7 +2,14 @@ module Sapphire
2
2
  module DSL
3
3
  module TestPlans
4
4
  def Run(item)
5
- Runner.instance.last_test_plan.Add(item)
5
+ if(item.is_a? Class)
6
+ if(item.new.is_a? Job)
7
+ job = item.new
8
+ system(job.PsExecPath + " " + job.Server + " -u " + job.User + " -p " + job.Password + " " + job.Path)
9
+ end
10
+ else
11
+ Runner.instance.last_test_plan.Add(item)
12
+ end
6
13
  end
7
14
  end
8
15
  end
@@ -47,7 +47,9 @@ module Sapphire
47
47
  end
48
48
 
49
49
  def execute
50
+ $stdout.puts ""
50
51
  @block.call
52
+ ConsoleReporter.new().OutputResults
51
53
  end
52
54
  end
53
55
  end
@@ -0,0 +1,28 @@
1
+ module Sapphire
2
+ module JobAbstractions
3
+ class Job
4
+
5
+ def Server
6
+ return ""
7
+ end
8
+
9
+ def User
10
+ return ""
11
+ end
12
+
13
+ def Password
14
+ return ""
15
+ end
16
+
17
+ def Path
18
+ return ""
19
+ end
20
+
21
+ def PsExecPath
22
+ return ""
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+
@@ -22,7 +22,6 @@ module Sapphire
22
22
  return control.Equals(arg)
23
23
  end
24
24
  end
25
-
26
25
  end
27
26
  end
28
27
  end
@@ -0,0 +1,53 @@
1
+ module Sapphire
2
+ module Testing
3
+ class ConsoleReporter < Reporter
4
+
5
+ def PrintItem(result, depth)
6
+ Indent(depth)
7
+
8
+ if result.type == 'pass'
9
+ $stdout.puts result.text.green
10
+ elsif result.type == 'pending'
11
+ $stdout.puts result.text.yellow
12
+ Indent(depth+1)
13
+ $stdout.puts " ## Not Yet Implemented ##"
14
+ else
15
+ $stdout.puts result.text.red
16
+ Indent(depth+1)
17
+ $stdout.puts result.message
18
+ end
19
+ end
20
+
21
+ def PrintHeader()
22
+ $stdout.puts ""
23
+ end
24
+
25
+ def PrintFooter()
26
+ $stdout.puts ""
27
+ $stdout.puts "Finished in " + self.time.round(2).to_s + " seconds."
28
+ $stdout.puts "Test Count: " + self.test_count.to_s
29
+ $stdout.puts "Passing: " + self.passing_count.to_s.green
30
+ $stdout.puts "Failing: " + self.failing_count.to_s.red
31
+ $stdout.puts "Pending: " + self.pending_count.to_s.yellow
32
+ end
33
+
34
+ def Indent(depth)
35
+ (1..depth).each do
36
+ $stdout.print "\t"
37
+ end
38
+ end
39
+
40
+ def InsertLineBreak()
41
+ $stdout.puts ""
42
+ end
43
+
44
+ def PrePrint
45
+
46
+ end
47
+
48
+ def PostPrint
49
+
50
+ end
51
+ end
52
+ end
53
+ end
@@ -5,22 +5,21 @@ module Sapphire
5
5
  start = Time.now
6
6
  begin
7
7
  if(self.value.is_a? Pending)
8
- self.AddResult(ResultTree.new(self.text, TestResult.new("pending", self.text, "Pending", "", Time.now - start, id)))
9
- puts "(pending) " + self.text + " (" + (Time.now - start).to_s + "s)"
8
+ self.AddResult(ResultTree.new(self.text, TestResult.new("pending", self, "Pending", "", Time.now - start, id)))
9
+ $stdout.print "*".yellow
10
10
  return
11
11
  end
12
12
  self.block.call
13
- self.AddResult(ResultTree.new(self.text, TestResult.new("pass", self.text, "Success", "", Time.now - start, id)))
14
- puts "(pass) " + self.text + " (" + (Time.now - start).to_s + "s)"
13
+ self.AddResult(ResultTree.new(self.text, TestResult.new("pass", self, "Success", "", Time.now - start, id)))
14
+ $stdout.print ".".green
15
15
  rescue => msg
16
-
17
16
  stack = ""
18
17
  msg.backtrace.each do |line|
19
18
  stack += "\r\n" + line
20
19
  end
21
20
 
22
- self.AddResult(ResultTree.new(self.text, TestResult.new("fail", self.text, msg.message, stack, Time.now - start, id)))
23
- puts "(fail) " + self.text + ": " + msg.message + " (" + (Time.now - start).to_s + "s)"
21
+ self.AddResult(ResultTree.new(self.text, TestResult.new("fail", self, msg.message, stack, Time.now - start, id)))
22
+ $stdout.print "F".red
24
23
  end
25
24
  end
26
25
  @result
@@ -0,0 +1,31 @@
1
+ module Sapphire
2
+ module Testing
3
+ class HtmlReporter < Reporter
4
+
5
+ def PrintHeader()
6
+
7
+ end
8
+
9
+ def Output(result, tabber)
10
+
11
+ end
12
+
13
+ def PrePrint
14
+
15
+ end
16
+
17
+ def PrintResult(entry)
18
+
19
+ end
20
+
21
+ def PostPrint
22
+
23
+ end
24
+
25
+ def PrintFooter()
26
+
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -78,6 +78,8 @@ module Sapphire
78
78
  end
79
79
  end
80
80
  end
81
+
82
+ true
81
83
  end
82
84
  end
83
85
  end
@@ -0,0 +1,140 @@
1
+ module Sapphire
2
+ module Testing
3
+ class Reporter
4
+
5
+ attr_reader :test_count
6
+ attr_reader :passing_count
7
+ attr_reader :failing_count
8
+ attr_reader :pending_count
9
+ attr_reader :time
10
+
11
+ def OutputResults()
12
+
13
+ self.GatherResults
14
+
15
+ not_passing = self.GetNotPassing
16
+
17
+ self.PrintHeader
18
+
19
+ not_passing.keys.each do |key|
20
+ self.PrePrint
21
+ self.PrintResult not_passing[key]
22
+ self.PostPrint
23
+ end
24
+
25
+ self.PrintFooter
26
+
27
+ end
28
+
29
+ def Output(result, depth)
30
+
31
+ self.PrintItem(result, depth)
32
+
33
+ result.results.each do |sub_result|
34
+ self.Output(sub_result, depth+1)
35
+ end
36
+ end
37
+
38
+ def PrintResult(entry)
39
+ if entry.item.is_a? Given or entry.item.is_a? Background
40
+ self.InsertLineBreak
41
+ self.Output entry, 0
42
+ self.InsertLineBreak
43
+ elsif entry.item.is_a? When
44
+ self.PrintItem entry.parent, 0
45
+ self.Output entry, 1
46
+ self.InsertLineBreak
47
+ else
48
+ self.PrintResult entry.parent
49
+ end
50
+ end
51
+
52
+ def GatherResults()
53
+ @test_count = 0
54
+ @passing_count = 0
55
+ @failing_count = 0
56
+ @pending_count = 0
57
+ @time = 0
58
+
59
+ Runner.instance.scenarios.each do |scenario|
60
+ item = scenario.result
61
+ @time += item.time
62
+ item.results.each do |result|
63
+ output = self.Count result
64
+ @test_count += output[:tests]
65
+ @passing_count += output[:passing]
66
+ @failing_count += output[:failing]
67
+ @pending_count += output[:pending]
68
+ @time += result.time
69
+ end
70
+ end
71
+ end
72
+
73
+ def Count(result)
74
+ test_count = 1
75
+ passing_count = 0
76
+ failing_count = 0
77
+ pending_count = 0
78
+
79
+ if result.type == 'pass'
80
+ passing_count += 1
81
+ elsif result.type == 'pending'
82
+ pending_count += 1
83
+ else
84
+ failing_count += 1
85
+ end
86
+
87
+ result.results.each do |sub_result|
88
+ output = self.Count(sub_result)
89
+
90
+ test_count += output[:tests]
91
+ passing_count += output[:passing]
92
+ failing_count += output[:failing]
93
+ pending_count += output[:pending]
94
+ end
95
+
96
+ { :tests => test_count, :passing => passing_count, :failing => failing_count, :pending => pending_count }
97
+ end
98
+
99
+ def GetNotPassing
100
+
101
+ results = {}
102
+
103
+ Runner.instance.scenarios.each do |scenario|
104
+ results = results.merge(self.RecurseResult(scenario.result))
105
+ end
106
+
107
+ results
108
+ end
109
+
110
+ def RecurseResult(result)
111
+ results = {}
112
+
113
+ result.results.each do |r|
114
+ result_passes = r.type == "pass"
115
+ if !result_passes and (r.item.is_a? Given or r.item.is_a? When or r.item.is_a? Background)
116
+ results = results.merge({ r => r })
117
+ next
118
+ elsif !result_passes and (r.item.is_a? And or r.item.parent.is_a? Given)
119
+ results = results.merge({ r.parent => r.parent })
120
+ next
121
+ elsif !result_passes and (r.item.is_a? And and r.parent.item.is_a? When)
122
+ results = results.merge({ r.parent => r.parent })
123
+ next
124
+ elsif !result_passes and (r.item.is_a? Then)
125
+ results = results.merge({ r.parent => r.parent })
126
+ next
127
+ elsif !result_passes and (r.item.is_a? And and r.parent.item.is_a? Then)
128
+ results = results.merge({ r.parent.parent => r.parent.parent })
129
+ next
130
+ else
131
+ results = results.merge(self.RecurseResult(r))
132
+ end
133
+ end
134
+
135
+ results
136
+ end
137
+
138
+ end
139
+ end
140
+ end
@@ -4,18 +4,24 @@ module Sapphire
4
4
 
5
5
  attr_accessor :results
6
6
  attr_accessor :type
7
+ attr_accessor :text
8
+ attr_accessor :message
9
+ attr_accessor :stack
10
+ attr_accessor :time
11
+ attr_accessor :parent
12
+ attr_accessor :item
7
13
 
8
14
  def initialize(text, result)
9
15
 
10
16
  @type = 'pass'
11
- @execution_time = 0
17
+ @time = 0
12
18
 
13
19
  if(result != nil)
14
20
  self.type = result.type
15
21
  @iconCls = "accept" if result.type == "pass"
16
22
  @iconCls = "delete" if result.type == "fail"
17
23
  @iconCls = "error" if result.type == "pending"
18
- @execution_time = result.execution_time
24
+ @time = result.execution_time
19
25
  @expanded = true
20
26
  @message = result.message
21
27
  @stack = result.stack
@@ -27,6 +33,7 @@ module Sapphire
27
33
  end
28
34
 
29
35
  def AddChild(node)
36
+ node.parent = self
30
37
  @results << node
31
38
  @leaf = false
32
39
  end
@@ -5,6 +5,8 @@ module Sapphire
5
5
  attr_reader :results
6
6
  attr_accessor :myId
7
7
  attr_reader :type
8
+ attr_reader :time
9
+ attr_reader :parent
8
10
 
9
11
  def initialize(text)
10
12
  @text = text
@@ -12,10 +14,13 @@ module Sapphire
12
14
  @leaf = true
13
15
  @myId = -1
14
16
  @type = 'pass'
17
+ @time = 0
15
18
  end
16
19
 
17
20
  def AddChild(result)
21
+ result.parent = self
18
22
  @results << result
23
+ @time += result.time
19
24
  end
20
25
 
21
26
  def set_id(id)
@@ -5,14 +5,14 @@ module Sapphire
5
5
  attr_reader :execution_time
6
6
  attr_reader :message
7
7
  attr_reader :myId
8
- attr_reader :text
8
+ attr_reader :item
9
9
  attr_reader :type
10
10
  attr_reader :stack
11
11
  attr_reader :message
12
12
 
13
- def initialize(type, text, message, stack, execution_time, id)
13
+ def initialize(type, item, message, stack, execution_time, id)
14
14
  @myId = id
15
- @text = text
15
+ @item = item
16
16
  @execution_time = execution_time
17
17
  @message = message
18
18
  @stack = stack
@@ -3,6 +3,9 @@ module Sapphire
3
3
  module TestRunnerAdapter
4
4
 
5
5
  def execute(id)
6
+ @failures = []
7
+ @pendings = []
8
+ @success = []
6
9
 
7
10
  self.backgrounds.each do |b|
8
11
 
@@ -53,7 +56,6 @@ module Sapphire
53
56
  end
54
57
 
55
58
  end
56
-
57
59
  end
58
60
  end
59
61
  end
@@ -1,3 +1,3 @@
1
1
  module Sapphire
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sapphire
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-01 00:00:00.000000000Z
12
+ date: 2011-09-22 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: albacore
16
- requirement: &9316620 !ruby/object:Gem::Requirement
15
+ name: selenium-webdriver
16
+ requirement: &9278508 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *9316620
24
+ version_requirements: *9278508
25
25
  - !ruby/object:Gem::Dependency
26
- name: selenium-webdriver
27
- requirement: &9316344 !ruby/object:Gem::Requirement
26
+ name: colorize
27
+ requirement: &9278172 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *9316344
35
+ version_requirements: *9278172
36
36
  - !ruby/object:Gem::Dependency
37
- name: activesupport
38
- requirement: &9316080 !ruby/object:Gem::Requirement
37
+ name: win32console
38
+ requirement: &9277848 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,12 +43,13 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *9316080
46
+ version_requirements: *9277848
47
47
  description: An automated web acceptance test framework for non-technical resources
48
48
  using selenium-wedriver.
49
49
  email:
50
50
  - marcus.bratton@gmail.com
51
- executables: []
51
+ executables:
52
+ - sapphire
52
53
  extensions: []
53
54
  extra_rdoc_files: []
54
55
  files:
@@ -58,6 +59,8 @@ files:
58
59
  - lib/sapphire/DataAbstractions/Database.rb
59
60
  - lib/sapphire/DataAbstractions/NonQuery.rb
60
61
  - lib/sapphire/DataAbstractions/Query.rb
62
+ - lib/sapphire/DSL/Browser/Accept.rb
63
+ - lib/sapphire/DSL/Browser/AlertBox.rb
61
64
  - lib/sapphire/DSL/Browser/Browser.rb
62
65
  - lib/sapphire/DSL/Browser/Check.rb
63
66
  - lib/sapphire/DSL/Browser/Clear.rb
@@ -115,6 +118,7 @@ files:
115
118
  - lib/sapphire/DSL/TestPlans/PathHandler.rb
116
119
  - lib/sapphire/DSL/TestPlans/Run.rb
117
120
  - lib/sapphire/DSL/TestPlans/TestPlan.rb
121
+ - lib/sapphire/JobAbstractions/Job.rb
118
122
  - lib/sapphire/Strategies/ClassStrategy.rb
119
123
  - lib/sapphire/Strategies/DefaultStrategy.rb
120
124
  - lib/sapphire/Strategies/Evaluation.rb
@@ -122,8 +126,11 @@ files:
122
126
  - lib/sapphire/Strategies/NullModifier.rb
123
127
  - lib/sapphire/Strategies/Strategy.rb
124
128
  - lib/sapphire/Strategies/SymbolStrategy.rb
129
+ - lib/sapphire/Testing/ConsoleReporter.rb
125
130
  - lib/sapphire/Testing/Executable.rb
131
+ - lib/sapphire/Testing/HtmlReporter.rb
126
132
  - lib/sapphire/Testing/RakeTask.rb
133
+ - lib/sapphire/Testing/Reporter.rb
127
134
  - lib/sapphire/Testing/ResultList.rb
128
135
  - lib/sapphire/Testing/ResultTree.rb
129
136
  - lib/sapphire/Testing/RSpecRunner.rb
@@ -148,6 +155,7 @@ files:
148
155
  - lib/sapphire/WebAbstractions/Controls/TextBox.rb
149
156
  - lib/sapphire/WebAbstractions/Controls/Title.rb
150
157
  - lib/sapphire.rb
158
+ - bin/sapphire
151
159
  homepage: http://github.com/MarcusTheBold/Sapphire/
152
160
  licenses: []
153
161
  post_install_message: