contact_manager 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +20 -0
- data/README.md +143 -0
- data/VERSION +1 -0
- data/app/contact_manager/launch.rb +3 -0
- data/app/contact_manager/model/contact.rb +39 -0
- data/app/contact_manager/model/contact_presenter.rb +47 -0
- data/app/contact_manager/model/contact_repository.rb +30 -0
- data/app/contact_manager/view/app_view.rb +70 -0
- data/app/contact_manager/view/contact_form.rb +134 -0
- data/app/contact_manager/view/contact_manager_menu_bar.rb +63 -0
- data/app/contact_manager/view/contact_table.rb +73 -0
- data/app/contact_manager.rb +25 -0
- data/bin/contact_manager +13 -0
- data/config/warble.rb +183 -0
- data/db/database.sqlite3 +0 -0
- data/db/db.rb +9 -0
- data/db/migrate/20220411211513_create_contacts.rb +17 -0
- data/db/migrate.rb +10 -0
- data/icons/linux/Contact Manager.png +0 -0
- data/icons/macosx/Contact Manager.icns +0 -0
- data/icons/windows/Contact Manager.ico +0 -0
- data/vendor/jars/org/yaml/snakeyaml/1.28/snakeyaml-1.28.jar +0 -0
- metadata +168 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: da527969ce6fd98138bdef3127469852a8b33c366f380e1a882cb5fdc89f5624
|
4
|
+
data.tar.gz: 2ee57d438aed53cc3c21bf0100e9e2826a1e89e64688ef4d7aa837910978c0ea
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 85aa0ae30fd630b7a51b3264781e35c1a05aa1d99a394aae054e172097aa389bbfece26bb54c7723c5bc7f37de56511ca0672854ce3f643c23d881342f3c2904
|
7
|
+
data.tar.gz: 11d3cf705f2bf0eee3b1de13f8f810f035467fd5342f3681c2fafa0a1c19c29448c43101bdc517553bc862112397c5bfa226ff1926838eeb2b2cadf3f41a1945
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2022 Andy Maleh
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
# <img src="https://raw.githubusercontent.com/AndyObtiva/contact_manager/master/icons/linux/Contact%20Manager.png" height=85 /> Contact Manager 1.0.0
|
2
|
+
## [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-swt/master/images/glimmer-logo-hi-res.png" height=40 /> Glimmer Application](https://github.com/AndyObtiva/glimmer-dsl-swt)
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/contact_manager.svg)](http://badge.fury.io/rb/contact_manager)
|
4
|
+
|
5
|
+
Contact Manager is a [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) sample leveraging [SQLite DB](https://www.sqlite.org/index.html) via [ActiveRecord](https://rubygems.org/gems/activerecord).
|
6
|
+
|
7
|
+
![Contact Manager Screenshot](/screenshots/contact-manager.gif)
|
8
|
+
|
9
|
+
## Setup
|
10
|
+
|
11
|
+
### Option 1: Install Native Executable Package
|
12
|
+
|
13
|
+
[<img src="https://raw.githubusercontent.com/AndyObtiva/contact_manager/master/icons/linux/Contact%20Manager.png" height=40 /> Contact Manager 1.0.0 (Mac Catalina 10.15.7 x86_64 DMG)](https://www.dropbox.com/s/swc0jl7joy29m84/Contact%20Manager-1.0.0-x64-catalina-10.15.7.dmg?dl=1)
|
14
|
+
|
15
|
+
[<img src="https://raw.githubusercontent.com/AndyObtiva/contact_manager/master/icons/linux/Contact%20Manager.png" height=40 /> Contact Manager 1.0.0 (Windows 10.0.19043 x86_64 MSI)](https://www.dropbox.com/s/tan8hbv3qk959t7/Contact%20Manager-1.0.0-x64-Windows-10.0.19043.msi?dl=1)
|
16
|
+
|
17
|
+
[<img src="https://raw.githubusercontent.com/AndyObtiva/contact_manager/master/icons/linux/Contact%20Manager.png" height=40 /> Contact Manager 1.0.0 (Linux x86_64 DEB)](https://www.dropbox.com/s/v6pckxcpw4quafx/contact-manager_1.0.0-1_amd64.deb?dl=1)
|
18
|
+
|
19
|
+
[<img src="https://raw.githubusercontent.com/AndyObtiva/contact_manager/master/icons/linux/Contact%20Manager.png" height=40 /> Contact Manager 1.0.0 (Linux x86_64 RPM)](https://www.dropbox.com/s/4dby42ux7ebyv6n/contact-manager-1.0.0-1.x86_64.rpm?dl=1)
|
20
|
+
|
21
|
+
### Option 2: Install Ruby Gem
|
22
|
+
|
23
|
+
Start by setting up [JDK 18](https://www.oracle.com/java/technologies/downloads) & [JRuby 9.3.3.0](https://www.jruby.org/) (+ [RVM](http://rvm.io/) on Mac/Linux) just as per [Glimmer DSL for SWT prerequisites](https://github.com/AndyObtiva/glimmer-dsl-swt#pre-requisites).
|
24
|
+
|
25
|
+
Install Ruby gem:
|
26
|
+
|
27
|
+
```
|
28
|
+
gem install contact_manager -v1.0.0
|
29
|
+
```
|
30
|
+
|
31
|
+
Run:
|
32
|
+
|
33
|
+
```
|
34
|
+
contact_manager
|
35
|
+
```
|
36
|
+
|
37
|
+
### Option 3: Clone Project Locally
|
38
|
+
|
39
|
+
Start by setting up [JDK 18](https://www.oracle.com/java/technologies/downloads) & [JRuby 9.3.3.0](https://www.jruby.org/) (+ [RVM](http://rvm.io/) on Mac/Linux) just as per [Glimmer DSL for SWT prerequisites](https://github.com/AndyObtiva/glimmer-dsl-swt#pre-requisites).
|
40
|
+
|
41
|
+
Clone:
|
42
|
+
|
43
|
+
```
|
44
|
+
git clone https://github.com/AndyObtiva/contact_manager.git
|
45
|
+
```
|
46
|
+
|
47
|
+
Change directory:
|
48
|
+
|
49
|
+
```
|
50
|
+
cd contact_manager
|
51
|
+
```
|
52
|
+
|
53
|
+
Bundle:
|
54
|
+
|
55
|
+
```
|
56
|
+
bundle
|
57
|
+
```
|
58
|
+
|
59
|
+
Run:
|
60
|
+
|
61
|
+
```
|
62
|
+
glimmer run
|
63
|
+
```
|
64
|
+
|
65
|
+
Or run with the binary script:
|
66
|
+
|
67
|
+
```
|
68
|
+
bin/contact_manager
|
69
|
+
```
|
70
|
+
|
71
|
+
You can [package a native executable](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md) DMG on Mac:
|
72
|
+
|
73
|
+
```
|
74
|
+
glimmer "package[dmg]"
|
75
|
+
```
|
76
|
+
|
77
|
+
You can [package a native executable](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md) MSI on Windows (assuming you followed [MSI related setup instructions](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md)):
|
78
|
+
|
79
|
+
```
|
80
|
+
glimmer "package[msi]"
|
81
|
+
```
|
82
|
+
|
83
|
+
You can [package a native executable](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md) DEB on debian-based Linux distros:
|
84
|
+
|
85
|
+
```
|
86
|
+
glimmer "package[deb]"
|
87
|
+
```
|
88
|
+
|
89
|
+
You can [package a native executable](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md) RPM on redhat-based Linux distros:
|
90
|
+
|
91
|
+
```
|
92
|
+
glimmer "package[rpm]"
|
93
|
+
```
|
94
|
+
|
95
|
+
## Software Architecture & Design
|
96
|
+
|
97
|
+
Contact Manager follows the [Model-View-Presenter](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter) flavor of [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller), so the View communicates to the Model via a Presenter, which is an enhanced Controller that enables bidirectional attribute data-binding between the Model and the View.
|
98
|
+
|
99
|
+
The View uses `contact_form`, `contact_table`, and `contact_manager_menu_bar` custom widgets (components)
|
100
|
+
|
101
|
+
The Model layer includes a `Contact` and `ContactRepository` ([DDD Repository Pattern](https://www.domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf)) in addition to `ContactPresenter` (which is both a Controller and a Model at a higher level).
|
102
|
+
|
103
|
+
`Contact` follows the [Active Record Pattern](https://en.wikipedia.org/wiki/Active_record_pattern) for [Object Relational Mapping](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) to store objects in a [SQLite](https://www.sqlite.org/index.html) relational database.
|
104
|
+
|
105
|
+
The Contact Manager graphical user interface leverages the [Master-Detail Interface Pattern](https://en.wikipedia.org/wiki/Master%E2%80%93detail_interface).
|
106
|
+
|
107
|
+
The database is stored at `~/db/
|
108
|
+
|
109
|
+
## TODO
|
110
|
+
|
111
|
+
[TODO.md](TODO.md)
|
112
|
+
|
113
|
+
## Change Log
|
114
|
+
|
115
|
+
[CHANGELOG.md](CHANGELOG.md)
|
116
|
+
|
117
|
+
## Contributing
|
118
|
+
|
119
|
+
- Check out the latest master to make sure the feature hasn't been
|
120
|
+
implemented or the bug hasn't been fixed yet.
|
121
|
+
- Check out the issue tracker to make sure someone already hasn't
|
122
|
+
requested it and/or contributed it.
|
123
|
+
- Fork the project.
|
124
|
+
- Start a feature/bugfix branch.
|
125
|
+
- Commit and push until you are happy with your contribution.
|
126
|
+
- Make sure to add tests for it. This is important so I don't break it
|
127
|
+
in a future version unintentionally.
|
128
|
+
- Please try not to mess with the Rakefile, version, or history. If
|
129
|
+
you want to have your own version, or is otherwise necessary, that
|
130
|
+
is fine, but please isolate to its own commit so I can cherry-pick
|
131
|
+
around it.
|
132
|
+
|
133
|
+
## Copyright
|
134
|
+
|
135
|
+
[MIT](LICENSE.txt)
|
136
|
+
|
137
|
+
Copyright (c) 2022 Andy Maleh. See [LICENSE.txt](LICENSE.txt) for further details.
|
138
|
+
|
139
|
+
--
|
140
|
+
|
141
|
+
[<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=40 />](https://github.com/AndyObtiva/glimmer) Built with [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) (JRuby Desktop Development GUI Library)
|
142
|
+
|
143
|
+
Contact Manager logo was made by [Freepik](https://www.flaticon.com/authors/freepik) from [www.flaticon.com](http://www.flaticon.com)
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'db/db'
|
2
|
+
|
3
|
+
class Contact < ActiveRecord::Base
|
4
|
+
STATES = [ 'AK', 'AL', 'AR', 'AZ', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'GA',
|
5
|
+
'HI', 'IA', 'ID', 'IL', 'IN', 'KS', 'KY', 'LA', 'MA', 'MD', 'ME',
|
6
|
+
'MI', 'MN', 'MO', 'MS', 'MT', 'NC', 'ND', 'NE', 'NH', 'NJ', 'NM',
|
7
|
+
'NV', 'NY', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC', 'SD', 'TN', 'TX',
|
8
|
+
'UT', 'VA', 'VT', 'WA', 'WI', 'WV', 'WY']
|
9
|
+
PROVINCES = ['NL', 'PE', 'NS', 'NB', 'QC', 'ON', 'MB', 'SK', 'AB', 'BC', 'YT', 'NT', 'NU']
|
10
|
+
|
11
|
+
validates :first_name, presence: true
|
12
|
+
validates :last_name, presence: true
|
13
|
+
validates :email, format: {with: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i, message: 'must be a valid email address'}, allow_blank: true
|
14
|
+
validates :phone, format: {with: /\A[(]?[0-9]{3}[)]?[ -\.\/0-9]{7,9}\z/, message: 'must be a valid phone number'}, allow_blank: true
|
15
|
+
validates :zip_or_postal_code, format: {with: /\A[a-z0-9][0-9][a-z0-9][ 0-9][a-z0-9][a-z0-9]?[0-9]?\z/i, message: 'must be a valid phone number'}, allow_blank: true
|
16
|
+
validate :email_or_phone_is_present
|
17
|
+
|
18
|
+
def address
|
19
|
+
address_fields = [street, city, state_or_province, zip_or_postal_code, country]
|
20
|
+
address_fields.map { |field| field.blank? ? nil : field }.compact.join(', ')
|
21
|
+
end
|
22
|
+
|
23
|
+
def country_options
|
24
|
+
['', 'Canada', 'USA']
|
25
|
+
end
|
26
|
+
|
27
|
+
def state_or_province_options
|
28
|
+
(PROVINCES + [''] + STATES)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def email_or_phone_is_present
|
34
|
+
if email.blank? && phone.blank?
|
35
|
+
errors.add(:email, 'must be present unless phone is present')
|
36
|
+
errors.add(:phone, 'must be present unless email is present')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'contact_manager/model/contact'
|
2
|
+
require 'contact_manager/model/contact_repository'
|
3
|
+
|
4
|
+
# ContactPresenter is an enhanced Controller that also
|
5
|
+
# enables bidirectional data-binding of contact attributes
|
6
|
+
class ContactPresenter
|
7
|
+
attr_accessor :contacts, :query, :current_contact
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
renew_current_contact
|
11
|
+
self.contacts = ContactRepository.instance.all
|
12
|
+
|
13
|
+
# Monitor Contact collection changes
|
14
|
+
# the after_commit hook executes the block under a different object
|
15
|
+
# binding, so we must use `this` to access self
|
16
|
+
this = self
|
17
|
+
Contact.after_commit(on: [:create, :update, :destroy]) do
|
18
|
+
this.contacts = ContactRepository.instance.all
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def query=(query_value)
|
23
|
+
@query = query_value
|
24
|
+
self.contacts = ContactRepository.instance.search(query_value)
|
25
|
+
end
|
26
|
+
|
27
|
+
def renew_current_contact
|
28
|
+
self.current_contact = Contact.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def save_current_contact
|
32
|
+
current_contact.save.tap do |saved|
|
33
|
+
renew_current_contact if saved
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def destroy_current_contact
|
38
|
+
if current_contact&.persisted?
|
39
|
+
current_contact.destroy
|
40
|
+
renew_current_contact
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def destroy_all_contacts
|
45
|
+
ContactRepository.instance.destroy_all_contacts
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'contact_manager/model/contact'
|
3
|
+
|
4
|
+
class ContactRepository
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def all
|
8
|
+
Contact.all
|
9
|
+
end
|
10
|
+
|
11
|
+
def search(query_value)
|
12
|
+
if query_value.present?
|
13
|
+
attribute_names = Contact.new.attributes.keys
|
14
|
+
conditions = attribute_names.reduce('') do |conditions, attribute|
|
15
|
+
if conditions.blank?
|
16
|
+
conditions += "lower(#{attribute}) like ?"
|
17
|
+
else
|
18
|
+
conditions += " OR lower(#{attribute}) like ?"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
Contact.where(conditions, *(["%#{query_value.downcase}%"]*attribute_names.count))
|
22
|
+
else
|
23
|
+
all
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def destroy_all_contacts
|
28
|
+
Contact.destroy_all
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'contact_manager/model/contact_presenter'
|
2
|
+
|
3
|
+
require 'contact_manager/view/contact_manager_menu_bar'
|
4
|
+
require 'contact_manager/view/contact_form'
|
5
|
+
require 'contact_manager/view/contact_table'
|
6
|
+
|
7
|
+
class ContactManager
|
8
|
+
module View
|
9
|
+
class AppView
|
10
|
+
include Glimmer::UI::Application
|
11
|
+
|
12
|
+
before_body do
|
13
|
+
@contact_presenter = ContactPresenter.new
|
14
|
+
|
15
|
+
@display = display {
|
16
|
+
on_about do
|
17
|
+
display_about_dialog
|
18
|
+
end
|
19
|
+
|
20
|
+
on_preferences do
|
21
|
+
display_about_dialog
|
22
|
+
end
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
body {
|
27
|
+
shell {
|
28
|
+
grid_layout
|
29
|
+
|
30
|
+
image File.join(APP_ROOT, 'icons', 'windows', "Contact Manager.ico") if OS.windows?
|
31
|
+
image File.join(APP_ROOT, 'icons', 'linux', "Contact Manager.png") unless OS.windows?
|
32
|
+
text "Contact Manager"
|
33
|
+
|
34
|
+
@contact_form = contact_form(contact_presenter: @contact_presenter) {
|
35
|
+
layout_data {
|
36
|
+
horizontal_alignment :fill
|
37
|
+
grab_excess_horizontal_space true
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
contact_table(
|
42
|
+
contact_presenter: @contact_presenter,
|
43
|
+
reset_validations_action: @contact_form.method(:reset_validations),
|
44
|
+
) {
|
45
|
+
layout_data {
|
46
|
+
horizontal_alignment :fill
|
47
|
+
grab_excess_horizontal_space true
|
48
|
+
vertical_alignment :fill
|
49
|
+
grab_excess_vertical_space true
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
contact_manager_menu_bar(
|
54
|
+
contact_presenter: @contact_presenter,
|
55
|
+
about_action: method(:display_about_dialog),
|
56
|
+
save_contact_action: @contact_form.method(:save_contact),
|
57
|
+
reset_validations_action: @contact_form.method(:reset_validations),
|
58
|
+
)
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
def display_about_dialog
|
63
|
+
message_box(body_root) {
|
64
|
+
text 'About'
|
65
|
+
message "Contact Manager #{VERSION}\n\n#{LICENSE}"
|
66
|
+
}.open
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
class ContactManager
|
2
|
+
module View
|
3
|
+
class ContactForm
|
4
|
+
include Glimmer::UI::CustomWidget
|
5
|
+
|
6
|
+
options :contact_presenter
|
7
|
+
|
8
|
+
body {
|
9
|
+
composite {
|
10
|
+
grid_layout {
|
11
|
+
num_columns 2
|
12
|
+
make_columns_equal_width true
|
13
|
+
margin_width 0
|
14
|
+
margin_height 0
|
15
|
+
vertical_spacing 0
|
16
|
+
}
|
17
|
+
|
18
|
+
form_column {
|
19
|
+
form_field(:first_name)
|
20
|
+
form_field(:last_name)
|
21
|
+
form_field(:email)
|
22
|
+
form_field(:phone)
|
23
|
+
}
|
24
|
+
|
25
|
+
form_column {
|
26
|
+
form_field(:street)
|
27
|
+
form_field(:city)
|
28
|
+
form_field(:state_or_province, editor: :combo, editor_args: :read_only, property: :selection)
|
29
|
+
form_field(:zip_or_postal_code)
|
30
|
+
form_field(:country, editor: :combo, editor_args: :read_only, property: :selection)
|
31
|
+
}
|
32
|
+
|
33
|
+
composite { # having a composite ensures padding around button
|
34
|
+
layout_data {
|
35
|
+
horizontal_span 2
|
36
|
+
horizontal_alignment :fill
|
37
|
+
grab_excess_horizontal_space true
|
38
|
+
}
|
39
|
+
|
40
|
+
grid_layout {
|
41
|
+
margin_height 0
|
42
|
+
}
|
43
|
+
|
44
|
+
button {
|
45
|
+
layout_data {
|
46
|
+
horizontal_alignment :fill
|
47
|
+
grab_excess_horizontal_space true
|
48
|
+
}
|
49
|
+
|
50
|
+
text 'Save Contact'
|
51
|
+
|
52
|
+
on_widget_selected do
|
53
|
+
save_contact
|
54
|
+
end
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
def form_column(&content)
|
61
|
+
composite { |the_composite|
|
62
|
+
layout_data {
|
63
|
+
horizontal_alignment :fill
|
64
|
+
vertical_alignment :fill
|
65
|
+
grab_excess_horizontal_space true
|
66
|
+
grab_excess_vertical_space true
|
67
|
+
}
|
68
|
+
|
69
|
+
grid_layout {
|
70
|
+
num_columns 2
|
71
|
+
make_columns_equal_width false
|
72
|
+
}
|
73
|
+
|
74
|
+
content.call(the_composite)
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def form_field(field, editor: :text, editor_args: [], property: :text)
|
79
|
+
@form_field_labels ||= {}
|
80
|
+
@form_field_labels[field] = label {
|
81
|
+
layout_data {
|
82
|
+
width_hint 120
|
83
|
+
}
|
84
|
+
|
85
|
+
text field.to_s.gsub('_', ' ').titlecase
|
86
|
+
}
|
87
|
+
|
88
|
+
@form_field_texts ||= {}
|
89
|
+
@form_field_texts[field] = send(editor, *editor_args) {
|
90
|
+
layout_data {
|
91
|
+
width_hint 150
|
92
|
+
horizontal_alignment :fill
|
93
|
+
grab_excess_horizontal_space true
|
94
|
+
}
|
95
|
+
|
96
|
+
# use nested data-binding to monitor change of contact
|
97
|
+
# in addition to contact field
|
98
|
+
send(property) <=> [contact_presenter, "current_contact.#{field}"]
|
99
|
+
|
100
|
+
on_key_pressed do |event|
|
101
|
+
save_contact if event.keyCode == swt(:cr)
|
102
|
+
end
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
def save_contact
|
107
|
+
if contact_presenter.save_current_contact
|
108
|
+
reset_validations
|
109
|
+
else
|
110
|
+
show_validations
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def reset_validations
|
115
|
+
contact_presenter.current_contact.attributes.keys.each do |attribute_name|
|
116
|
+
@form_field_labels[attribute_name.to_sym]&.foreground = :black
|
117
|
+
@form_field_labels[attribute_name.to_sym]&.tool_tip_text = nil
|
118
|
+
end
|
119
|
+
focus_first_field
|
120
|
+
end
|
121
|
+
|
122
|
+
def show_validations
|
123
|
+
contact_presenter.current_contact.errors.errors.each do |error|
|
124
|
+
@form_field_labels[error.attribute].foreground = :red
|
125
|
+
@form_field_labels[error.attribute].tool_tip_text = error.full_message
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def focus_first_field
|
130
|
+
@form_field_texts[:first_name].set_focus
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class ContactManager
|
2
|
+
module View
|
3
|
+
class ContactManagerMenuBar
|
4
|
+
include Glimmer::UI::CustomWidget
|
5
|
+
|
6
|
+
ACCELERATOR_KEY = OS.mac? ? :command : :ctrl
|
7
|
+
|
8
|
+
options :contact_presenter, :about_action, :save_contact_action, :reset_validations_action
|
9
|
+
|
10
|
+
body {
|
11
|
+
menu_bar {
|
12
|
+
menu {
|
13
|
+
text '&Contact'
|
14
|
+
|
15
|
+
menu_item {
|
16
|
+
text '&New'
|
17
|
+
accelerator ACCELERATOR_KEY, :n
|
18
|
+
|
19
|
+
on_widget_selected do
|
20
|
+
contact_presenter.renew_current_contact
|
21
|
+
reset_validations_action.call
|
22
|
+
end
|
23
|
+
}
|
24
|
+
|
25
|
+
menu_item {
|
26
|
+
text '&Save'
|
27
|
+
accelerator ACCELERATOR_KEY, :s
|
28
|
+
|
29
|
+
on_widget_selected do
|
30
|
+
save_contact_action.call
|
31
|
+
end
|
32
|
+
}
|
33
|
+
|
34
|
+
menu_item {
|
35
|
+
text '&Delete All...'
|
36
|
+
|
37
|
+
on_widget_selected do
|
38
|
+
result = message_box(:yes, :no) {
|
39
|
+
text 'Delete All'
|
40
|
+
message 'Are you sure you want to delete all your contacts?'
|
41
|
+
}.open
|
42
|
+
contact_presenter.destroy_all_contacts if result == swt(:yes)
|
43
|
+
end
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
menu {
|
48
|
+
text '&Help'
|
49
|
+
|
50
|
+
menu_item {
|
51
|
+
text '&About...'
|
52
|
+
|
53
|
+
on_widget_selected do
|
54
|
+
about_action.call
|
55
|
+
end
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class ContactManager
|
2
|
+
module View
|
3
|
+
class ContactTable
|
4
|
+
include Glimmer::UI::CustomWidget
|
5
|
+
|
6
|
+
options :contact_presenter, :reset_validations_action
|
7
|
+
|
8
|
+
body {
|
9
|
+
composite {
|
10
|
+
grid_layout {
|
11
|
+
margin_height 0
|
12
|
+
}
|
13
|
+
|
14
|
+
text(:search) {
|
15
|
+
layout_data {
|
16
|
+
horizontal_alignment :fill
|
17
|
+
grab_excess_horizontal_space true
|
18
|
+
}
|
19
|
+
|
20
|
+
text <=> [contact_presenter, :query]
|
21
|
+
}
|
22
|
+
|
23
|
+
table {
|
24
|
+
layout_data {
|
25
|
+
height_hint 250
|
26
|
+
horizontal_alignment :fill
|
27
|
+
grab_excess_horizontal_space true
|
28
|
+
vertical_alignment :fill
|
29
|
+
grab_excess_vertical_space true
|
30
|
+
}
|
31
|
+
|
32
|
+
table_column {
|
33
|
+
text 'First Name'
|
34
|
+
width 120
|
35
|
+
}
|
36
|
+
table_column {
|
37
|
+
text 'Last Name'
|
38
|
+
width 120
|
39
|
+
}
|
40
|
+
table_column {
|
41
|
+
text 'Email'
|
42
|
+
width 180
|
43
|
+
}
|
44
|
+
table_column {
|
45
|
+
text 'Phone'
|
46
|
+
width 120
|
47
|
+
}
|
48
|
+
table_column {
|
49
|
+
text 'Address'
|
50
|
+
width 320
|
51
|
+
}
|
52
|
+
|
53
|
+
# Ensure converting to Array on read because contacts is an ActiveRecord collection,
|
54
|
+
# but an Array object is required by Glimmer DSL for SWT table data-binding logic
|
55
|
+
items <=> [contact_presenter, :contacts, on_read: :to_a, column_properties: [:first_name, :last_name, :email, :phone, :address]]
|
56
|
+
|
57
|
+
selection <=> [contact_presenter, :current_contact, after_write: reset_validations_action]
|
58
|
+
|
59
|
+
menu {
|
60
|
+
menu_item {
|
61
|
+
text '&Delete'
|
62
|
+
|
63
|
+
on_widget_selected do
|
64
|
+
contact_presenter.destroy_current_contact
|
65
|
+
end
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('..', __FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.expand_path('../..', __FILE__))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'bundler/setup'
|
6
|
+
Bundler.require(:default)
|
7
|
+
rescue
|
8
|
+
# this runs when packaged as a gem (no bundler)
|
9
|
+
require 'glimmer-dsl-swt'
|
10
|
+
# add more gems if needed
|
11
|
+
require 'active_record'
|
12
|
+
require 'activerecord-jdbcsqlite3-adapter'
|
13
|
+
end
|
14
|
+
|
15
|
+
class ContactManager
|
16
|
+
include Glimmer
|
17
|
+
|
18
|
+
APP_ROOT = File.expand_path('../..', __FILE__)
|
19
|
+
VERSION = File.read(File.join(APP_ROOT, 'VERSION'))
|
20
|
+
LICENSE = File.read(File.join(APP_ROOT, 'LICENSE.txt'))
|
21
|
+
Display.app_name = 'Contact Manager'
|
22
|
+
Display.app_version = ContactManager::VERSION
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'contact_manager/view/app_view'
|
data/bin/contact_manager
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env jruby
|
2
|
+
|
3
|
+
runner = File.expand_path('../../app/contact_manager/launch.rb', __FILE__)
|
4
|
+
|
5
|
+
# Detect if inside a JAR file or not
|
6
|
+
if runner.include?('uri:classloader')
|
7
|
+
require runner
|
8
|
+
else
|
9
|
+
require 'glimmer/launcher'
|
10
|
+
|
11
|
+
launcher = Glimmer::Launcher.new([runner] + ARGV)
|
12
|
+
launcher.launch
|
13
|
+
end
|
data/config/warble.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
|
2
|
+
# Disable Rake-environment-task framework detection by uncommenting/setting to false
|
3
|
+
# Warbler.framework_detection = false
|
4
|
+
|
5
|
+
# Warbler web application assembly configuration file
|
6
|
+
Warbler::Config.new do |config|
|
7
|
+
# Features: additional options controlling how the jar is built.
|
8
|
+
# Currently the following features are supported:
|
9
|
+
# - *gemjar*: package the gem repository in a jar file in WEB-INF/lib
|
10
|
+
# - *executable*: embed a web server and make the war executable
|
11
|
+
# - *runnable*: allows to run bin scripts e.g. `java -jar my.war -S rake -T`
|
12
|
+
# - *compiled*: compile .rb files to .class files
|
13
|
+
# config.features = %w(gemjar)
|
14
|
+
|
15
|
+
# Application directories to be included in the webapp.
|
16
|
+
config.dirs = %w(app bin config db docs fonts icons images lib package script sounds vendor videos)
|
17
|
+
|
18
|
+
# Additional files/directories to include, above those in config.dirs
|
19
|
+
config.includes = FileList['LICENSE.txt', 'VERSION']
|
20
|
+
|
21
|
+
# Additional files/directories to exclude
|
22
|
+
# config.excludes = FileList["lib/tasks/*"]
|
23
|
+
|
24
|
+
# Additional Java .jar files to include. Note that if .jar files are placed
|
25
|
+
# in lib (and not otherwise excluded) then they need not be mentioned here.
|
26
|
+
# JRuby and JRuby-Rack are pre-loaded in this list. Be sure to include your
|
27
|
+
# own versions if you directly set the value
|
28
|
+
# config.java_libs += FileList["lib/java/*.jar"]
|
29
|
+
|
30
|
+
# Loose Java classes and miscellaneous files to be included.
|
31
|
+
# config.java_classes = FileList["target/classes/**.*"]
|
32
|
+
|
33
|
+
# One or more pathmaps defining how the java classes should be copied into
|
34
|
+
# the archive. The example pathmap below accompanies the java_classes
|
35
|
+
# configuration above. See http://rake.rubyforge.org/classes/String.html#M000017
|
36
|
+
# for details of how to specify a pathmap.
|
37
|
+
# config.pathmaps.java_classes << "%{target/classes/,}p"
|
38
|
+
|
39
|
+
# Bundler support is built-in. If Warbler finds a Gemfile in the
|
40
|
+
# project directory, it will be used to collect the gems to bundle
|
41
|
+
# in your application. If you wish to explicitly disable this
|
42
|
+
# functionality, uncomment here.
|
43
|
+
# config.bundler = false
|
44
|
+
|
45
|
+
# An array of Bundler groups to avoid including in the war file.
|
46
|
+
# Defaults to ["development", "test", "assets"].
|
47
|
+
# config.bundle_without = []
|
48
|
+
|
49
|
+
# Other gems to be included. If you don't use Bundler or a gemspec
|
50
|
+
# file, you need to tell Warbler which gems your application needs
|
51
|
+
# so that they can be packaged in the archive.
|
52
|
+
# For Rails applications, the Rails gems are included by default
|
53
|
+
# unless the vendor/rails directory is present.
|
54
|
+
# config.gems += ["activerecord-jdbcmysql-adapter", "jruby-openssl"]
|
55
|
+
# config.gems << "tzinfo"
|
56
|
+
|
57
|
+
# Uncomment this if you don't want to package rails gem.
|
58
|
+
# config.gems -= ["rails"]
|
59
|
+
|
60
|
+
# The most recent versions of gems are used.
|
61
|
+
# You can specify versions of gems by using a hash assignment:
|
62
|
+
# config.gems["rails"] = "4.2.5"
|
63
|
+
|
64
|
+
# You can also use regexps or Gem::Dependency objects for flexibility or
|
65
|
+
# finer-grained control.
|
66
|
+
# config.gems << /^sinatra-/
|
67
|
+
# config.gems << Gem::Dependency.new("sinatra", "= 1.4.7")
|
68
|
+
|
69
|
+
# Include gem dependencies not mentioned specifically. Default is
|
70
|
+
# true, uncomment to turn off.
|
71
|
+
# config.gem_dependencies = false
|
72
|
+
|
73
|
+
# Array of regular expressions matching relative paths in gems to be
|
74
|
+
# excluded from the war. Defaults to empty, but you can set it like
|
75
|
+
# below, which excludes test files.
|
76
|
+
# config.gem_excludes = [/^(test|spec)\//]
|
77
|
+
|
78
|
+
# Pathmaps for controlling how application files are copied into the archive
|
79
|
+
# config.pathmaps.application = ["WEB-INF/%p"]
|
80
|
+
|
81
|
+
# Name of the archive (without the extension). Defaults to the basename
|
82
|
+
# of the project directory.
|
83
|
+
# config.jar_name = "mywar"
|
84
|
+
|
85
|
+
# File extension for the archive. Defaults to either 'jar' or 'war'.
|
86
|
+
# config.jar_extension = "jar"
|
87
|
+
|
88
|
+
# Destionation for the created archive. Defaults to project's root directory.
|
89
|
+
config.autodeploy_dir = "dist/"
|
90
|
+
|
91
|
+
# Name of the MANIFEST.MF template for the war file. Defaults to a simple
|
92
|
+
# MANIFEST.MF that contains the version of Warbler used to create the war file.
|
93
|
+
# config.manifest_file = "config/MANIFEST.MF"
|
94
|
+
|
95
|
+
# When using the 'compiled' feature and specified, only these Ruby
|
96
|
+
# files will be compiled. Default is to compile all \.rb files in
|
97
|
+
# the application.
|
98
|
+
# config.compiled_ruby_files = FileList['app/**/*.rb']
|
99
|
+
|
100
|
+
# Determines if ruby files in supporting gems will be compiled.
|
101
|
+
# Ignored unless compile feature is used.
|
102
|
+
# config.compile_gems = false
|
103
|
+
|
104
|
+
# When set it specify the bytecode version for compiled class files
|
105
|
+
# config.bytecode_version = "1.6"
|
106
|
+
|
107
|
+
# When set to true, Warbler will override the value of ENV['GEM_HOME'] even it
|
108
|
+
# has already been set. When set to false it will use any existing value of
|
109
|
+
# GEM_HOME if it is set.
|
110
|
+
# config.override_gem_home = true
|
111
|
+
|
112
|
+
# Allows for specifing custom executables
|
113
|
+
# config.executable = ["rake", "bin/rake"]
|
114
|
+
|
115
|
+
# Sets default (prefixed) parameters for the executables
|
116
|
+
# config.executable_params = "do:something"
|
117
|
+
|
118
|
+
# If set to true, moves jar files into WEB-INF/lib. Prior to version 1.4.2 of Warbler this was done
|
119
|
+
# by default. But since 1.4.2 this config defaults to false. It may need to be set to true for
|
120
|
+
# web servers that do not explode the WAR file.
|
121
|
+
# Alternatively, this option can be set to a regular expression, which will
|
122
|
+
# act as a jar selector -- only jar files that match the pattern will be
|
123
|
+
# included in the archive.
|
124
|
+
# config.move_jars_to_webinf_lib = false
|
125
|
+
|
126
|
+
# === War files only below here ===
|
127
|
+
|
128
|
+
# Embedded webserver to use with the 'executable' feature. Currently supported
|
129
|
+
# webservers are:
|
130
|
+
# - *jetty* - Embedded Jetty from Eclipse
|
131
|
+
# config.webserver = 'jetty'
|
132
|
+
|
133
|
+
# Path to the pre-bundled gem directory inside the war file. Default
|
134
|
+
# is 'WEB-INF/gems'. Specify path if gems are already bundled
|
135
|
+
# before running Warbler. This also sets 'gem.path' inside web.xml.
|
136
|
+
# config.gem_path = "WEB-INF/vendor/bundler_gems"
|
137
|
+
|
138
|
+
# Files for WEB-INF directory (next to web.xml). This contains
|
139
|
+
# web.xml by default. If there is an .erb-File it will be processed
|
140
|
+
# with webxml-config. You may want to exclude this file via
|
141
|
+
# config.excludes.
|
142
|
+
# config.webinf_files += FileList["jboss-web.xml"]
|
143
|
+
|
144
|
+
# Files to be included in the root of the webapp. Note that files in public
|
145
|
+
# will have the leading 'public/' part of the path stripped during staging.
|
146
|
+
# config.public_html = FileList["public/**/*", "doc/**/*"]
|
147
|
+
|
148
|
+
# Pathmaps for controlling how public HTML files are copied into the .war
|
149
|
+
# config.pathmaps.public_html = ["%{public/,}p"]
|
150
|
+
|
151
|
+
# Value of RAILS_ENV for the webapp -- default as shown below
|
152
|
+
# config.webxml.rails.env = ENV['RAILS_ENV'] || 'production'
|
153
|
+
|
154
|
+
# Public ROOT mapping, by default assets are copied into .war ROOT directory.
|
155
|
+
# config.public.root = ''
|
156
|
+
|
157
|
+
# Application booter to use, either :rack or :rails (autodetected by default)
|
158
|
+
# config.webxml.booter = :rails
|
159
|
+
|
160
|
+
# When using the :rack booter, "Rackup" script to use.
|
161
|
+
# - For 'rackup.path', the value points to the location of the rackup
|
162
|
+
# script in the web archive file. You need to make sure this file
|
163
|
+
# gets included in the war, possibly by adding it to config.includes
|
164
|
+
# or config.webinf_files above.
|
165
|
+
# - For 'rackup', the rackup script you provide as an inline string
|
166
|
+
# is simply embedded in web.xml.
|
167
|
+
# The script is evaluated in a Rack::Builder to load the application.
|
168
|
+
# Examples:
|
169
|
+
# config.webxml.rackup.path = 'WEB-INF/hello.ru'
|
170
|
+
# config.webxml.rackup = %{require './lib/demo'; run Rack::Adapter::Camping.new(Demo)}
|
171
|
+
# config.webxml.rackup = require 'cgi' && CGI::escapeHTML(File.read("config.ru"))
|
172
|
+
|
173
|
+
# Control the pool of Rails runtimes. Leaving unspecified means
|
174
|
+
# the pool will grow as needed to service requests. It is recommended
|
175
|
+
# that you fix these values when running a production server!
|
176
|
+
# If you're using threadsafe! mode, you probably don't want to set these values,
|
177
|
+
# since 1 runtime(default for threadsafe mode) will be enough.
|
178
|
+
# config.webxml.jruby.min.runtimes = 2
|
179
|
+
# config.webxml.jruby.max.runtimes = 4
|
180
|
+
|
181
|
+
# JNDI data source name
|
182
|
+
# config.webxml.jndi = 'jdbc/rails'
|
183
|
+
end
|
data/db/database.sqlite3
ADDED
Binary file
|
data/db/db.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'jdbc/sqlite3'
|
3
|
+
Jdbc::SQLite3.load_driver
|
4
|
+
require 'activerecord-jdbcsqlite3-adapter' if defined? JRUBY_VERSION
|
5
|
+
@connection = ActiveRecord::Base.establish_connection(
|
6
|
+
adapter: 'sqlite3',
|
7
|
+
database: File.join(Dir.home, 'db/contact_manager.sqlite3')
|
8
|
+
)
|
9
|
+
require 'db/migrate'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
class CreateContacts < ActiveRecord::Migration[6.1]
|
4
|
+
def change
|
5
|
+
create_table :contacts do |t|
|
6
|
+
t.string :first_name
|
7
|
+
t.string :last_name
|
8
|
+
t.string :email
|
9
|
+
t.string :phone
|
10
|
+
t.string :street
|
11
|
+
t.string :city
|
12
|
+
t.string :state_or_province
|
13
|
+
t.string :zip_or_postal_code
|
14
|
+
t.string :country
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/db/migrate.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
migrate_dir = File.expand_path('../migrate', __FILE__)
|
2
|
+
Dir.glob(File.join(migrate_dir, '**', '*.rb')).each {|migration| require migration}
|
3
|
+
|
4
|
+
ActiveRecord::Migration[6.1].descendants.each do |migration|
|
5
|
+
begin
|
6
|
+
migration.migrate(:up)
|
7
|
+
rescue => e
|
8
|
+
raise e unless e.full_message.match(/table "[^"]+" already exists/)
|
9
|
+
end
|
10
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: contact_manager
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andy Maleh
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-06-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: 4.23.1.4
|
19
|
+
name: glimmer-dsl-swt
|
20
|
+
prerelease: false
|
21
|
+
type: :runtime
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.23.1.4
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 6.1.5
|
33
|
+
name: activerecord
|
34
|
+
prerelease: false
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 6.1.5
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '61.1'
|
47
|
+
name: activerecord-jdbcsqlite3-adapter
|
48
|
+
prerelease: false
|
49
|
+
type: :runtime
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '61.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 3.5.0
|
61
|
+
name: rspec
|
62
|
+
prerelease: false
|
63
|
+
type: :development
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.5.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - '='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 2.4.9
|
75
|
+
name: juwelier
|
76
|
+
prerelease: false
|
77
|
+
type: :development
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.4.9
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - '='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 2.0.5
|
89
|
+
name: warbler
|
90
|
+
prerelease: false
|
91
|
+
type: :development
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 2.0.5
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
name: simplecov
|
104
|
+
prerelease: false
|
105
|
+
type: :development
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Contact Manager is a Glimmer DSL for SWT sample leveraging SQLite DB
|
112
|
+
via ActiveRecord.
|
113
|
+
email: andy.am@gmail.com
|
114
|
+
executables:
|
115
|
+
- contact_manager
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files:
|
118
|
+
- LICENSE.txt
|
119
|
+
- README.md
|
120
|
+
files:
|
121
|
+
- LICENSE.txt
|
122
|
+
- README.md
|
123
|
+
- VERSION
|
124
|
+
- app/contact_manager.rb
|
125
|
+
- app/contact_manager/launch.rb
|
126
|
+
- app/contact_manager/model/contact.rb
|
127
|
+
- app/contact_manager/model/contact_presenter.rb
|
128
|
+
- app/contact_manager/model/contact_repository.rb
|
129
|
+
- app/contact_manager/view/app_view.rb
|
130
|
+
- app/contact_manager/view/contact_form.rb
|
131
|
+
- app/contact_manager/view/contact_manager_menu_bar.rb
|
132
|
+
- app/contact_manager/view/contact_table.rb
|
133
|
+
- bin/contact_manager
|
134
|
+
- config/warble.rb
|
135
|
+
- db/database.sqlite3
|
136
|
+
- db/db.rb
|
137
|
+
- db/migrate.rb
|
138
|
+
- db/migrate/20220411211513_create_contacts.rb
|
139
|
+
- icons/linux/Contact Manager.png
|
140
|
+
- icons/macosx/Contact Manager.icns
|
141
|
+
- icons/windows/Contact Manager.ico
|
142
|
+
- vendor/jars/org/yaml/snakeyaml/1.28/snakeyaml-1.28.jar
|
143
|
+
homepage: http://github.com/AndyObtiva/contact_manager
|
144
|
+
licenses:
|
145
|
+
- MIT
|
146
|
+
metadata: {}
|
147
|
+
post_install_message:
|
148
|
+
rdoc_options: []
|
149
|
+
require_paths:
|
150
|
+
- vendor
|
151
|
+
- lib
|
152
|
+
- app
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
requirements: []
|
164
|
+
rubygems_version: 3.2.29
|
165
|
+
signing_key:
|
166
|
+
specification_version: 4
|
167
|
+
summary: Contact Manager
|
168
|
+
test_files: []
|