contact_manager 1.0.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.
- 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
|
+
[](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
|
+

|
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: []
|