clockface 1.0.0.beta

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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +210 -0
  4. data/Rakefile +22 -0
  5. data/app/assets/config/clockface_manifest.js +2 -0
  6. data/app/assets/images/clockface/clockface.svg +34 -0
  7. data/app/assets/javascripts/clockface/application.js +17 -0
  8. data/app/assets/javascripts/clockface/flash.js +7 -0
  9. data/app/assets/javascripts/clockface/sorttable.js +494 -0
  10. data/app/assets/stylesheets/clockface/application.scss +80 -0
  11. data/app/assets/stylesheets/clockface/application/_fonts.scss +2 -0
  12. data/app/assets/stylesheets/clockface/application/colors.scss +8 -0
  13. data/app/assets/stylesheets/clockface/application/flash.scss +6 -0
  14. data/app/assets/stylesheets/clockface/application/footer.scss +37 -0
  15. data/app/assets/stylesheets/clockface/application/nav.scss +51 -0
  16. data/app/assets/stylesheets/clockface/events/delete.scss +45 -0
  17. data/app/assets/stylesheets/clockface/events/event_form.scss +62 -0
  18. data/app/assets/stylesheets/clockface/events/index.scss +56 -0
  19. data/app/assets/stylesheets/clockface/tasks/delete.scss +29 -0
  20. data/app/assets/stylesheets/clockface/tasks/index.scss +47 -0
  21. data/app/assets/stylesheets/clockface/tasks/task_form.scss +20 -0
  22. data/app/controllers/clockface/application_controller.rb +20 -0
  23. data/app/controllers/clockface/events_controller.rb +151 -0
  24. data/app/controllers/clockface/root_controller.rb +7 -0
  25. data/app/controllers/clockface/tasks_controller.rb +137 -0
  26. data/app/events/clockface/application_job.rb +4 -0
  27. data/app/helpers/clockface/application_helper.rb +4 -0
  28. data/app/helpers/clockface/config_helper.rb +32 -0
  29. data/app/helpers/clockface/events_helper.rb +37 -0
  30. data/app/helpers/clockface/logging_helper.rb +12 -0
  31. data/app/mailers/clockface/application_mailer.rb +6 -0
  32. data/app/models/clockface/application_record.rb +7 -0
  33. data/app/models/clockface/event.rb +179 -0
  34. data/app/models/clockface/task.rb +12 -0
  35. data/app/presenters/clockface/events_presenter.rb +48 -0
  36. data/app/services/clockface/event_validation_interactor.rb +35 -0
  37. data/app/services/clockface/task_validation_interactor.rb +25 -0
  38. data/app/views/clockface/application/_flash.html.erb +25 -0
  39. data/app/views/clockface/application/_footer.html.erb +15 -0
  40. data/app/views/clockface/application/_nav.html.erb +19 -0
  41. data/app/views/clockface/events/_event_form.html.erb +130 -0
  42. data/app/views/clockface/events/delete.html.erb +124 -0
  43. data/app/views/clockface/events/edit.html.erb +14 -0
  44. data/app/views/clockface/events/index.html.erb +108 -0
  45. data/app/views/clockface/events/new.html.erb +14 -0
  46. data/app/views/clockface/tasks/_task_form.html.erb +57 -0
  47. data/app/views/clockface/tasks/delete.html.erb +83 -0
  48. data/app/views/clockface/tasks/edit.html.erb +14 -0
  49. data/app/views/clockface/tasks/index.html.erb +70 -0
  50. data/app/views/clockface/tasks/new.html.erb +14 -0
  51. data/app/views/layouts/clockface/application.html.erb +27 -0
  52. data/config/locales/en.yml +158 -0
  53. data/config/routes.rb +15 -0
  54. data/db/migrate/20170528230549_create_clockface_tasks.rb +10 -0
  55. data/db/migrate/20170528234810_create_clockface_events.rb +20 -0
  56. data/lib/clockface.rb +135 -0
  57. data/lib/clockface/engine.rb +79 -0
  58. data/lib/clockface/version.rb +3 -0
  59. data/lib/clockwork/database_events/synchronizer.rb +73 -0
  60. data/lib/tasks/clockface_tasks.rake +4 -0
  61. metadata +199 -0
@@ -0,0 +1,15 @@
1
+ Clockface::Engine.routes.draw do
2
+ root to: "root#index"
3
+
4
+ resources :tasks, except: [:show] do
5
+ # Rails routes don't include a visible deletion page, only a `#destroy`
6
+ # endpoint. Define a custom one
7
+ get :delete, to: "tasks#delete"
8
+ end
9
+
10
+ resources :events, except: [:show] do
11
+ # Rails routes don't include a visible deletion page, only a `#destroy`
12
+ # endpoint. Define a custom one
13
+ get :delete, to: "events#delete"
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ class CreateClockfaceTasks < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :clockface_tasks do |t|
4
+ t.timestamps
5
+ t.string :name, null: false
6
+ t.text :description
7
+ t.string :command, null: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ class CreateClockfaceEvents < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :clockface_events do |t|
4
+ t.timestamps
5
+
6
+ t.references :clockface_task, foreign_key: true
7
+ t.boolean :enabled, default: false
8
+ t.boolean :skip_first_run, default: false
9
+ t.string :tenant
10
+ t.datetime :last_triggered_at
11
+ t.integer :period_value, null: false
12
+ t.string :period_units, null: false
13
+ t.integer :day_of_week
14
+ t.integer :hour
15
+ t.integer :minute
16
+ t.string :time_zone
17
+ t.string :if_condition
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,135 @@
1
+ require "clockwork"
2
+ require "clockwork/database_events"
3
+
4
+ require_relative "./clockwork/database_events/synchronizer"
5
+ require_relative "../app/helpers/clockface/config_helper"
6
+ require_relative "../app/helpers/clockface/logging_helper"
7
+
8
+ require "clockface/engine"
9
+ require "clockface/version"
10
+
11
+ # This file is the glue that ties together the clockwork gem with the Clockface
12
+ # Engine functionality.
13
+ #
14
+ # Clockface uses the `sync_database_events` method provided by Clockwork to
15
+ # periodically refresh the list of events from a DB table.
16
+ #
17
+ # In the case of multi-tenancy, there needs to be one refresh event for each
18
+ # individual tenant, but the same concept applies.
19
+ #
20
+ # Here's what happens -
21
+ #
22
+ # 1. Users require this file in their individual `clock.rb` files
23
+ # which in turn loads the engine directly. The engine is called by Rails
24
+ # during the startup process but we also need to load it here as part of the
25
+ # environment that's loaded by the clock process
26
+ #
27
+ # 2. As mentioned above, Clockwork provides the `sync_database_events` method
28
+ # as part of its API. However, we want to make things as easy as possible for
29
+ # each user and we want to take care of error handling, logging, and updating
30
+ # records as well in a predictable fashion. The solution to that is to define
31
+ # *another* custom `sync_database_events` below, which calls the original
32
+ # Clockwork method. When users call `sync_database_events` it will hit this
33
+ # wrapper which will take care of all the above tasks and defer execution to
34
+ # the Clockwork method.
35
+ #
36
+ # 3. Clockwork doesn't support schema-based multi-tenancy. In order
37
+ # to get that we need to override the Synchronizer it uses to create a synch
38
+ # event for each individual tenant. That overriden synchronizer is loaded at
39
+ # the top of this file. See that file for further background
40
+
41
+ module Clockface
42
+ module Methods
43
+ # rubocop:disable Metrics/MethodLength
44
+ def sync_database_events(opts = {}, &block)
45
+ ::Clockwork.manager = ::Clockwork::DatabaseEvents::Manager.new
46
+
47
+ unless block_given?
48
+ raise "Please specify a block to Clockface::sync_database_events"
49
+ end
50
+
51
+ #
52
+ # Configure Clockwork
53
+ #
54
+
55
+ Clockwork.manager.configure do |config|
56
+ # The underlying Clockwork gem tries to set time zone in the following
57
+ # order
58
+ #
59
+ # a. Event-specific time
60
+ # b. Clockwork Configured time (Clockwork.manager.config[:tz])
61
+ # c. System Time
62
+ #
63
+ # Clockface enforces that each event *must* have a time zone. It
64
+ # defaults to the `clockface_time_zone` when the user doesn't choose one
65
+ #
66
+ # Clockface also sets the Clockwork configured time to be
67
+ # `clockface_time_zone` in case for some reason a user updates the DB
68
+ # record directly and bypasses our validations.
69
+ #
70
+ # Howevever this doesn't work as expected right now. See -
71
+ # https://github.com/Rykian/clockwork/issues/35
72
+ #
73
+ # As far as format, see explanation for time zone format in
74
+ # `Clockface::Event#tz`
75
+ config[:tz] = ActiveSupport::TimeZone::MAPPING[clockface_time_zone]
76
+ end
77
+
78
+ clockwork_opts =
79
+ { model: Clockface::Event, every: opts[:every] }
80
+
81
+ ::Clockwork.sync_database_events(clockwork_opts) do |event|
82
+ event_name = "\"#{event.name}\" (Event.id: #{event.id})"
83
+ tenant_tag = "[#{event.tenant}] " if event.tenant
84
+
85
+ unless event.enabled?
86
+ clockface_log(
87
+ :info,
88
+ "#{tenant_tag}Skipping disabled Event #{event_name}"
89
+ )
90
+
91
+ # This whole block is eventually invoked from
92
+ # `Clockwork::Event#execute` using `block.call(...)`. Using `return`
93
+ # inside a called object returns from the whole process, so we have
94
+ # to use `next` instead to return from just the block itself
95
+ # Further explanation: https://stackoverflow.com/a/1435781/2490003
96
+ next
97
+ end
98
+
99
+ begin
100
+ # We want to do 2 things here -
101
+ #
102
+ # 1. Update the timestamp. Do this before any event execution so
103
+ # that if this fails, we don't continue with execution
104
+ # 2. Execute the event
105
+ #
106
+ #
107
+ # In the case of multi-tenancy we want to execute both of the
108
+ # above in the context of the correct tenant.
109
+
110
+ clockface_log(:info, "#{tenant_tag}Running Event #{event_name}")
111
+
112
+ cmd = proc { event.update!(last_triggered_at: Time.zone.now) }
113
+
114
+ if clockface_multi_tenancy_enabled?
115
+ clockface_execute_in_tenant(event.tenant, cmd)
116
+ clockface_execute_in_tenant(event.tenant, block, [event])
117
+ else
118
+ cmd.call
119
+ yield(event)
120
+ end
121
+ rescue StandardError => e
122
+ clockface_log(
123
+ :error,
124
+ "#{tenant_tag}Error running Event #{event_name} -> #{e.message}"
125
+ )
126
+ end
127
+ end
128
+ end
129
+ # rubocop:enable Metrics/MethodLength
130
+ end
131
+
132
+ extend ::Clockface::ConfigHelper
133
+ extend ::Clockface::LoggingHelper
134
+ extend Methods
135
+ end
@@ -0,0 +1,79 @@
1
+ require "bootstrap-sass"
2
+ require "inline_svg"
3
+ require "interactor"
4
+
5
+ module Clockface
6
+ class Engine < ::Rails::Engine
7
+ isolate_namespace Clockface
8
+
9
+ config.generators do |generate|
10
+ generate.factory_girl true
11
+ generate.helper false
12
+ generate.javascript_engine false
13
+ generate.request_specs false
14
+ generate.routing_specs false
15
+ generate.stylesheets false
16
+ generate.test_framework :rspec
17
+ generate.view_specs false
18
+ end
19
+
20
+ # Ensure this initializer runs before the host applications initializers
21
+ # so that the config structure gets defined.
22
+ initializer "clockface.config", before: :load_config_initializers do |app|
23
+ ClockfaceConfig = Struct.new(
24
+ :time_zone,
25
+ :logger,
26
+ :tenant_list,
27
+ :current_tenant_proc,
28
+ :execute_in_tenant_proc
29
+ )
30
+
31
+ app.config.clockface = ClockfaceConfig.new
32
+ app.config.clockface.time_zone = Rails.application.config.time_zone
33
+ app.config.clockface.logger = Rails.logger
34
+
35
+ # Multi Tenancy
36
+ app.config.clockface.tenant_list = []
37
+ app.config.clockface.current_tenant_proc = nil
38
+ app.config.clockface.execute_in_tenant_proc = nil
39
+ end
40
+
41
+ # Ensure this initializer runs after the host applications initializers
42
+ # so it can verify what was configured
43
+ initializer "clockface.validate", after: :load_config_initializers do |app|
44
+ # Time Zone
45
+ time_zone = app.config.clockface.time_zone
46
+ valid_time_zones = ActiveSupport::TimeZone::MAPPING.keys
47
+ unless valid_time_zones.include?(time_zone)
48
+ raise "Invalid time zone #{time_zone}"
49
+ end
50
+
51
+ # Log
52
+ loggers = app.config.clockface.logger
53
+ loggers = [loggers] unless loggers.is_a?(Array)
54
+ methods = %i[debug info warn error fatal]
55
+ loggers.each do |logger|
56
+ methods.each do |m|
57
+ unless logger.respond_to?(m)
58
+ raise "At least one logger is invalid. Did not respond to `:#{m}`"
59
+ end
60
+ end
61
+ end
62
+
63
+ # Tenant List
64
+ app.config.clockface.tenant_list = app.config.clockface.tenant_list.uniq
65
+
66
+ # Current Tenant
67
+ p = app.config.clockface.current_tenant_proc
68
+ if app.config.clockface.tenant_list.any? && p.blank?
69
+ raise "`current_tenant_proc` must be defined for multi-tenant mode"
70
+ end
71
+
72
+ # Execute In Tenant
73
+ p = app.config.clockface.execute_in_tenant_proc
74
+ if app.config.clockface.tenant_list.any? && p.blank?
75
+ raise "`execute_in_tenant_proc` must be defined for multi-tenant mode"
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,3 @@
1
+ module Clockface
2
+ VERSION = "1.0.0.beta".freeze
3
+ end
@@ -0,0 +1,73 @@
1
+ require "clockwork/database_events"
2
+ require_relative "../../../app/helpers/clockface/config_helper"
3
+ require_relative "../../../app/helpers/clockface/logging_helper"
4
+
5
+ # Loaded from lib/clockface as part of the clock configuration
6
+ #
7
+ # Clockwork doesn't support schema-based multi-tenancy by default. To acheive
8
+ # functionality we need to have it create a synch event for each individual
9
+ # tenant
10
+ #
11
+ # This overrides the Synchronizer class in the native Clockwork implementation
12
+ # to do the following -
13
+ #
14
+ # 1. If multi-tenancy is enabled, create a synch event for each tenant
15
+ # 2. If not, just create one synch event (same Clockwork functionality)
16
+
17
+ module Clockwork
18
+ module DatabaseEvents
19
+ class Synchronizer
20
+ extend ::Clockface::ConfigHelper
21
+ extend ::Clockface::LoggingHelper
22
+
23
+ def self.setup(options = {}, &block_to_perform_on_event_trigger)
24
+ every = options.fetch(:every) do
25
+ raise KeyError, ":every must be set to the database sync frequency"
26
+ end
27
+
28
+ task_name = "sync_database_events"
29
+
30
+ #
31
+ # Multi-Tenant
32
+ #
33
+
34
+ if clockface_multi_tenancy_enabled?
35
+ clockface_tenant_list.each do |t|
36
+ event_store = EventStore.new(block_to_perform_on_event_trigger)
37
+
38
+ Clockwork.manager.every(every, "#{t}.#{task_name}") do
39
+ cmd = proc do
40
+ # 1. Pre-load `:task` association so it doesn't need to be
41
+ # re-queried
42
+ # 2. ActiveRecord lazily evaluates the query, so #all won't
43
+ # actually run against the DB when executed. Force it to
44
+ # execute by calling something on it (e.g. #to_a)
45
+ Clockface::Event.
46
+ includes(:task).
47
+ all.
48
+ tap(&:to_a)
49
+ end
50
+ models = clockface_execute_in_tenant(t, cmd)
51
+
52
+ clockface_log(:info, "[#{t}] Running #{t}.#{task_name}")
53
+ event_store.update(models)
54
+ end
55
+ end
56
+
57
+ return
58
+ end
59
+
60
+ #
61
+ # Single Tenant
62
+ #
63
+
64
+ event_store = EventStore.new(block_to_perform_on_event_trigger)
65
+
66
+ Clockwork.manager.every(every, task_name) do
67
+ clockface_log(:info, "Running #{task_name}")
68
+ event_store.update(Clockface::Event.all)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :clockface do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,199 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clockface
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.beta
5
+ platform: ruby
6
+ authors:
7
+ - Abhishek Chandrasekhar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-06-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bootstrap-sass
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: clockwork
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 2.0.3
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '2.0'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 2.0.3
61
+ - !ruby/object:Gem::Dependency
62
+ name: inline_svg
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.2'
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: 1.2.1
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '1.2'
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: 1.2.1
81
+ - !ruby/object:Gem::Dependency
82
+ name: interactor
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '3.1'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '3.1'
95
+ - !ruby/object:Gem::Dependency
96
+ name: sass-rails
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '3.2'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '3.2'
109
+ description: A Configuration UI for the Clockwork gem
110
+ email:
111
+ - me@abhchand.me
112
+ executables: []
113
+ extensions: []
114
+ extra_rdoc_files: []
115
+ files:
116
+ - MIT-LICENSE
117
+ - README.md
118
+ - Rakefile
119
+ - app/assets/config/clockface_manifest.js
120
+ - app/assets/images/clockface/clockface.svg
121
+ - app/assets/javascripts/clockface/application.js
122
+ - app/assets/javascripts/clockface/flash.js
123
+ - app/assets/javascripts/clockface/sorttable.js
124
+ - app/assets/stylesheets/clockface/application.scss
125
+ - app/assets/stylesheets/clockface/application/_fonts.scss
126
+ - app/assets/stylesheets/clockface/application/colors.scss
127
+ - app/assets/stylesheets/clockface/application/flash.scss
128
+ - app/assets/stylesheets/clockface/application/footer.scss
129
+ - app/assets/stylesheets/clockface/application/nav.scss
130
+ - app/assets/stylesheets/clockface/events/delete.scss
131
+ - app/assets/stylesheets/clockface/events/event_form.scss
132
+ - app/assets/stylesheets/clockface/events/index.scss
133
+ - app/assets/stylesheets/clockface/tasks/delete.scss
134
+ - app/assets/stylesheets/clockface/tasks/index.scss
135
+ - app/assets/stylesheets/clockface/tasks/task_form.scss
136
+ - app/controllers/clockface/application_controller.rb
137
+ - app/controllers/clockface/events_controller.rb
138
+ - app/controllers/clockface/root_controller.rb
139
+ - app/controllers/clockface/tasks_controller.rb
140
+ - app/events/clockface/application_job.rb
141
+ - app/helpers/clockface/application_helper.rb
142
+ - app/helpers/clockface/config_helper.rb
143
+ - app/helpers/clockface/events_helper.rb
144
+ - app/helpers/clockface/logging_helper.rb
145
+ - app/mailers/clockface/application_mailer.rb
146
+ - app/models/clockface/application_record.rb
147
+ - app/models/clockface/event.rb
148
+ - app/models/clockface/task.rb
149
+ - app/presenters/clockface/events_presenter.rb
150
+ - app/services/clockface/event_validation_interactor.rb
151
+ - app/services/clockface/task_validation_interactor.rb
152
+ - app/views/clockface/application/_flash.html.erb
153
+ - app/views/clockface/application/_footer.html.erb
154
+ - app/views/clockface/application/_nav.html.erb
155
+ - app/views/clockface/events/_event_form.html.erb
156
+ - app/views/clockface/events/delete.html.erb
157
+ - app/views/clockface/events/edit.html.erb
158
+ - app/views/clockface/events/index.html.erb
159
+ - app/views/clockface/events/new.html.erb
160
+ - app/views/clockface/tasks/_task_form.html.erb
161
+ - app/views/clockface/tasks/delete.html.erb
162
+ - app/views/clockface/tasks/edit.html.erb
163
+ - app/views/clockface/tasks/index.html.erb
164
+ - app/views/clockface/tasks/new.html.erb
165
+ - app/views/layouts/clockface/application.html.erb
166
+ - config/locales/en.yml
167
+ - config/routes.rb
168
+ - db/migrate/20170528230549_create_clockface_tasks.rb
169
+ - db/migrate/20170528234810_create_clockface_events.rb
170
+ - lib/clockface.rb
171
+ - lib/clockface/engine.rb
172
+ - lib/clockface/version.rb
173
+ - lib/clockwork/database_events/synchronizer.rb
174
+ - lib/tasks/clockface_tasks.rake
175
+ homepage: https://gitlab.com/abhchand/clockface
176
+ licenses:
177
+ - MIT
178
+ metadata: {}
179
+ post_install_message:
180
+ rdoc_options: []
181
+ require_paths:
182
+ - lib
183
+ required_ruby_version: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ required_rubygems_version: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - ">"
191
+ - !ruby/object:Gem::Version
192
+ version: 1.3.1
193
+ requirements: []
194
+ rubyforge_project:
195
+ rubygems_version: 2.6.10
196
+ signing_key:
197
+ specification_version: 4
198
+ summary: A Configuration UI for the Clockwork gem
199
+ test_files: []