incline 0.1.5
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/.gitignore +13 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +186 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +208 -0
- data/Rakefile +37 -0
- data/app/assets/fonts/incline/.keep +0 -0
- data/app/assets/images/incline/.keep +0 -0
- data/app/assets/images/incline/barcode-B.svg +181 -0
- data/app/assets/javascripts/incline/activate_classed_items.js +11 -0
- data/app/assets/javascripts/incline/application.js +30 -0
- data/app/assets/javascripts/incline/bootstrap-datepicker.js +1800 -0
- data/app/assets/javascripts/incline/datatables.js +22193 -0
- data/app/assets/javascripts/incline/escapeHtml.js +10 -0
- data/app/assets/javascripts/incline/inline_actions.js +479 -0
- data/app/assets/javascripts/incline/jquery.doubleScroll.js +112 -0
- data/app/assets/javascripts/incline/jquery.number.js +764 -0
- data/app/assets/javascripts/incline/regexMask.js +27 -0
- data/app/assets/javascripts/incline/select2/i18n/en.js +3 -0
- data/app/assets/javascripts/incline/select2/select2.full.js +6436 -0
- data/app/assets/stylesheets/incline/application.css +18 -0
- data/app/assets/stylesheets/incline/bootstrap-theme.min.css +5 -0
- data/app/assets/stylesheets/incline/custom.scss +279 -0
- data/app/assets/stylesheets/incline/datatables.css +494 -0
- data/app/assets/stylesheets/incline/datepicker3.css +790 -0
- data/app/assets/stylesheets/incline/select2.css +484 -0
- data/app/controllers/incline/access_groups_controller.rb +127 -0
- data/app/controllers/incline/access_test_controller.rb +30 -0
- data/app/controllers/incline/account_activations_controller.rb +28 -0
- data/app/controllers/incline/application_controller.rb +11 -0
- data/app/controllers/incline/contact_controller.rb +34 -0
- data/app/controllers/incline/password_resets_controller.rb +113 -0
- data/app/controllers/incline/security_controller.rb +100 -0
- data/app/controllers/incline/sessions_controller.rb +50 -0
- data/app/controllers/incline/users_controller.rb +304 -0
- data/app/controllers/incline/welcome_controller.rb +19 -0
- data/app/helpers/incline/.keep +0 -0
- data/app/mailers/incline/application_mailer_base.rb +11 -0
- data/app/mailers/incline/contact_form.rb +19 -0
- data/app/mailers/incline/user_mailer.rb +45 -0
- data/app/models/incline/access_group.rb +121 -0
- data/app/models/incline/access_group_group_member.rb +12 -0
- data/app/models/incline/access_group_user_member.rb +10 -0
- data/app/models/incline/action_group.rb +12 -0
- data/app/models/incline/action_security.rb +222 -0
- data/app/models/incline/contact_message.rb +37 -0
- data/app/models/incline/disable_info.rb +20 -0
- data/app/models/incline/password_reset.rb +14 -0
- data/app/models/incline/password_reset_request.rb +14 -0
- data/app/models/incline/user.rb +437 -0
- data/app/models/incline/user_login_history.rb +30 -0
- data/app/views/incline/access_groups/_details.json.jbuilder +10 -0
- data/app/views/incline/access_groups/_form.html.erb +19 -0
- data/app/views/incline/access_groups/_list.html.erb +60 -0
- data/app/views/incline/access_groups/_messages.json.jbuilder +6 -0
- data/app/views/incline/access_groups/edit.html.erb +2 -0
- data/app/views/incline/access_groups/index.html.erb +6 -0
- data/app/views/incline/access_groups/index.json.jbuilder +16 -0
- data/app/views/incline/access_groups/new.html.erb +2 -0
- data/app/views/incline/access_groups/show.html.erb +9 -0
- data/app/views/incline/access_groups/show.json.jbuilder +11 -0
- data/app/views/incline/contact/new.html.erb +22 -0
- data/app/views/incline/contact_form/contact.html.erb +16 -0
- data/app/views/incline/contact_form/contact.text.erb +13 -0
- data/app/views/incline/password_resets/edit.html.erb +16 -0
- data/app/views/incline/password_resets/new.html.erb +12 -0
- data/app/views/incline/security/_details.json.jbuilder +7 -0
- data/app/views/incline/security/_form.html.erb +20 -0
- data/app/views/incline/security/_list.html.erb +89 -0
- data/app/views/incline/security/_messages.json.jbuilder +6 -0
- data/app/views/incline/security/edit.html.erb +2 -0
- data/app/views/incline/security/index.html.erb +6 -0
- data/app/views/incline/security/index.json.jbuilder +16 -0
- data/app/views/incline/security/show.html.erb +31 -0
- data/app/views/incline/security/show.json.jbuilder +11 -0
- data/app/views/incline/sessions/new.html.erb +26 -0
- data/app/views/incline/user_mailer/account_activation.html.erb +7 -0
- data/app/views/incline/user_mailer/account_activation.text.erb +6 -0
- data/app/views/incline/user_mailer/invalid_password_reset.html.erb +3 -0
- data/app/views/incline/user_mailer/invalid_password_reset.text.erb +5 -0
- data/app/views/incline/user_mailer/password_reset.html.erb +8 -0
- data/app/views/incline/user_mailer/password_reset.text.erb +7 -0
- data/app/views/incline/users/_details.json.jbuilder +32 -0
- data/app/views/incline/users/_form.html.erb +21 -0
- data/app/views/incline/users/_list.html.erb +102 -0
- data/app/views/incline/users/_messages.json.jbuilder +6 -0
- data/app/views/incline/users/disable_confirm.html.erb +19 -0
- data/app/views/incline/users/edit.html.erb +5 -0
- data/app/views/incline/users/index.html.erb +6 -0
- data/app/views/incline/users/index.json.jbuilder +16 -0
- data/app/views/incline/users/new.html.erb +5 -0
- data/app/views/incline/users/show.html.erb +12 -0
- data/app/views/incline/users/show.json.jbuilder +11 -0
- data/app/views/incline/welcome/home.html.erb +5 -0
- data/app/views/layouts/application.html.erb +1 -0
- data/app/views/layouts/incline/_account_menu.html.erb +18 -0
- data/app/views/layouts/incline/_app_menu_anon.html.erb +1 -0
- data/app/views/layouts/incline/_app_menu_authenticated.html.erb +1 -0
- data/app/views/layouts/incline/_footer.html.erb +13 -0
- data/app/views/layouts/incline/_header.html.erb +21 -0
- data/app/views/layouts/incline/_html_mailer.html.erb +5 -0
- data/app/views/layouts/incline/_incline_app.html.erb +25 -0
- data/app/views/layouts/incline/_messages.html.erb +3 -0
- data/app/views/layouts/incline/_shim.html.erb +3 -0
- data/app/views/layouts/incline/_text_mailer.text.erb +1 -0
- data/app/views/layouts/incline/application.html.erb +1 -0
- data/app/views/layouts/mailer.html.erb +2 -0
- data/app/views/layouts/mailer.text.erb +2 -0
- data/bin/rails +12 -0
- data/bin/test_scaffold.sh +10 -0
- data/config/routes.rb +61 -0
- data/db/migrate/20170511230126_create_incline_users.rb +26 -0
- data/db/migrate/20170515003052_create_incline_access_groups.rb +10 -0
- data/db/migrate/20170515003221_create_incline_user_login_histories.rb +12 -0
- data/db/migrate/20170515150908_create_incline_access_group_user_members.rb +11 -0
- data/db/migrate/20170515151058_create_incline_access_group_group_members.rb +11 -0
- data/db/migrate/20170517193432_add_comments_to_incline_user.rb +5 -0
- data/db/migrate/20170622132700_create_incline_action_securities.rb +16 -0
- data/db/migrate/20170622172712_create_incline_action_groups.rb +11 -0
- data/db/migrate/20170622195742_add_non_standard_to_action_security.rb +5 -0
- data/db/migrate/20170622230422_add_visible_to_action_security.rb +5 -0
- data/db/seeds.rb +81 -0
- data/exe/new_incline_app +42 -0
- data/lib/generators/incline/install_generator.rb +259 -0
- data/lib/generators/incline/templates/_app_menu_anon.html.erb +1 -0
- data/lib/generators/incline/templates/_app_menu_authenticated.html.erb +1 -0
- data/lib/generators/incline/templates/incline_application.css +17 -0
- data/lib/generators/incline/templates/incline_application.html.erb +1 -0
- data/lib/generators/incline/templates/incline_application.js +12 -0
- data/lib/generators/incline/templates/incline_database.yml +25 -0
- data/lib/generators/incline/templates/incline_email.yml +20 -0
- data/lib/generators/incline/templates/incline_mailer.html.erb +2 -0
- data/lib/generators/incline/templates/incline_mailer.text.erb +2 -0
- data/lib/generators/incline/templates/incline_users.yml +64 -0
- data/lib/generators/incline/templates/incline_version.rb +3 -0
- data/lib/incline/auth_engine_base.rb +52 -0
- data/lib/incline/data_tables_request.rb +336 -0
- data/lib/incline/date_time_formats.rb +6 -0
- data/lib/incline/engine.rb +212 -0
- data/lib/incline/errors.rb +15 -0
- data/lib/incline/extensions/action_controller_base.rb +526 -0
- data/lib/incline/extensions/action_mailer_base.rb +66 -0
- data/lib/incline/extensions/action_view_base.rb +489 -0
- data/lib/incline/extensions/active_record_base.rb +308 -0
- data/lib/incline/extensions/application.rb +137 -0
- data/lib/incline/extensions/application_configuration.rb +50 -0
- data/lib/incline/extensions/connection_adapter.rb +55 -0
- data/lib/incline/extensions/date_time_value.rb +123 -0
- data/lib/incline/extensions/date_value.rb +77 -0
- data/lib/incline/extensions/decimal_value.rb +55 -0
- data/lib/incline/extensions/erb_scaffold_generator.rb +31 -0
- data/lib/incline/extensions/float_value.rb +59 -0
- data/lib/incline/extensions/form_builder.rb +617 -0
- data/lib/incline/extensions/integer_value.rb +54 -0
- data/lib/incline/extensions/jbuilder_generator.rb +38 -0
- data/lib/incline/extensions/jbuilder_template.rb +39 -0
- data/lib/incline/extensions/main_app.rb +40 -0
- data/lib/incline/extensions/numeric.rb +63 -0
- data/lib/incline/extensions/object.rb +31 -0
- data/lib/incline/extensions/resource_route_generator.rb +53 -0
- data/lib/incline/extensions/session.rb +113 -0
- data/lib/incline/extensions/string.rb +50 -0
- data/lib/incline/extensions/test_case.rb +764 -0
- data/lib/incline/extensions/time_zone_converter.rb +40 -0
- data/lib/incline/global_status.rb +236 -0
- data/lib/incline/helpers/route_hash_formatter.rb +46 -0
- data/lib/incline/json_log_formatter.rb +96 -0
- data/lib/incline/json_logger.rb +17 -0
- data/lib/incline/log.rb +153 -0
- data/lib/incline/number_formats.rb +17 -0
- data/lib/incline/recaptcha.rb +346 -0
- data/lib/incline/user_manager.rb +212 -0
- data/lib/incline/validators/email_validator.rb +45 -0
- data/lib/incline/validators/ip_address_validator.rb +32 -0
- data/lib/incline/validators/recaptcha_validator.rb +37 -0
- data/lib/incline/validators/safe_name_validator.rb +31 -0
- data/lib/incline/version.rb +3 -0
- data/lib/incline/work_path.rb +75 -0
- data/lib/incline.rb +197 -0
- data/lib/tasks/incline_tasks.rake +4 -0
- data/lib/templates/erb/scaffold/_form.html.erb +43 -0
- data/lib/templates/erb/scaffold/_list.html.erb +81 -0
- data/lib/templates/erb/scaffold/edit.html.erb +1 -0
- data/lib/templates/erb/scaffold/index.html.erb +6 -0
- data/lib/templates/erb/scaffold/new.html.erb +1 -0
- data/lib/templates/erb/scaffold/show.html.erb +34 -0
- data/lib/templates/jbuilder/scaffold/_details.json.jbuilder +20 -0
- data/lib/templates/jbuilder/scaffold/index.json.jbuilder +16 -0
- data/lib/templates/jbuilder/scaffold/show.json.jbuilder +16 -0
- data/lib/templates/rails/scaffold_controller/controller.rb +128 -0
- data/test/controllers/incline/access_groups_controller_test.rb +65 -0
- data/test/controllers/incline/access_test_controller_test.rb +53 -0
- data/test/controllers/incline/contact_controller_test.rb +32 -0
- data/test/controllers/incline/security_controller_test.rb +39 -0
- data/test/controllers/incline/welcome_controller_test.rb +16 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/javascripts/application.js +12 -0
- data/test/dummy/app/assets/stylesheets/application.css +17 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/.keep +0 -0
- data/test/dummy/app/models/.keep +0 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +1 -0
- data/test/dummy/app/views/layouts/incline/_app_menu_anon.html.erb +1 -0
- data/test/dummy/app/views/layouts/incline/_app_menu_authenticated.html.erb +1 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +2 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +2 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config/application.rb +38 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +34 -0
- data/test/dummy/config/email.yml +24 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +45 -0
- data/test/dummy/config/environments/production.rb +85 -0
- data/test/dummy/config/environments/test.rb +44 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +6 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/schema.rb +108 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/extensions/action_controller_base_extensions_test.rb +21 -0
- data/test/extensions/action_mailer_base_extensions_test.rb +20 -0
- data/test/extensions/action_view_base_extensions_test.rb +267 -0
- data/test/extensions/active_record_extensions_test.rb +173 -0
- data/test/extensions/application_configuration_extensions_test.rb +46 -0
- data/test/extensions/application_extensions_test.rb +23 -0
- data/test/extensions/connection_adapter_extensions_test.rb +54 -0
- data/test/extensions/date_time_value_extensions_test.rb +104 -0
- data/test/extensions/date_value_extensions_test.rb +102 -0
- data/test/extensions/decimal_value_extensions_test.rb +85 -0
- data/test/extensions/erb_scaffold_generator_extensions_test.rb +17 -0
- data/test/extensions/float_value_extensions_test.rb +78 -0
- data/test/extensions/form_builder_extensions_test.rb +28 -0
- data/test/extensions/integer_value_extensions_test.rb +78 -0
- data/test/extensions/jbuilder_generator_extensions_test.rb +21 -0
- data/test/extensions/jbuilder_template_extensions_test.rb +47 -0
- data/test/extensions/main_app_extensions_test.rb +55 -0
- data/test/extensions/numeric_extensions_test.rb +76 -0
- data/test/extensions/object_extensions_test.rb +104 -0
- data/test/extensions/session_extensions_test.rb +69 -0
- data/test/extensions/string_extensions_test.rb +32 -0
- data/test/extensions/test_case_extensions_test.rb +538 -0
- data/test/extensions/time_zone_converter_extensions_test.rb +10 -0
- data/test/fixtures/incline/access_group_group_members.yml +1 -0
- data/test/fixtures/incline/access_group_user_members.yml +1 -0
- data/test/fixtures/incline/access_groups.yml +13 -0
- data/test/fixtures/incline/action_groups.yml +6 -0
- data/test/fixtures/incline/action_securities.yml +18 -0
- data/test/fixtures/incline/user_login_histories.yml +1 -0
- data/test/fixtures/incline/users.yml +64 -0
- data/test/incline_test.rb +63 -0
- data/test/integration/incline/users_edit_test.rb +180 -0
- data/test/integration/incline/users_login_test.rb +105 -0
- data/test/integration/incline/users_signup_test.rb +147 -0
- data/test/integration/navigation_test.rb +11 -0
- data/test/lib/data_tables_request_test.rb +245 -0
- data/test/lib/date_time_formats_test.rb +111 -0
- data/test/lib/global_status_test.rb +89 -0
- data/test/lib/json_log_formatter_test.rb +43 -0
- data/test/lib/log_test.rb +36 -0
- data/test/lib/recaptcha_test.rb +75 -0
- data/test/lib/user_manager_test.rb +47 -0
- data/test/lib/work_path_test.rb +18 -0
- data/test/models/incline/access_group_group_member_test.rb +30 -0
- data/test/models/incline/access_group_test.rb +60 -0
- data/test/models/incline/access_group_user_member_test.rb +29 -0
- data/test/models/incline/action_group_test.rb +27 -0
- data/test/models/incline/action_security_test.rb +176 -0
- data/test/models/incline/contact_message_test.rb +66 -0
- data/test/models/incline/disable_info_test.rb +29 -0
- data/test/models/incline/password_reset_request_test.rb +35 -0
- data/test/models/incline/password_reset_test.rb +51 -0
- data/test/models/incline/user_login_history_test.rb +31 -0
- data/test/models/incline/user_test.rb +91 -0
- data/test/test_helper.rb +42 -0
- data/test/validators/email_validator_test.rb +102 -0
- data/test/validators/ip_address_validator_test.rb +107 -0
- data/test/validators/recaptcha_validator_test.rb +57 -0
- data/test/validators/safe_name_validator_test.rb +101 -0
- metadata +584 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
require 'active_record'
|
|
2
|
+
|
|
3
|
+
module Incline::Extensions
|
|
4
|
+
module ActiveRecordBase
|
|
5
|
+
|
|
6
|
+
def to_s # :nodoc:
|
|
7
|
+
if respond_to?(:name)
|
|
8
|
+
send :name
|
|
9
|
+
else
|
|
10
|
+
"ID = #{id}"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def inspect # :nodoc:
|
|
15
|
+
"#<#{self.class}:#{self.object_pointer} #{to_s}>"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# Tests for equality on ID if available.
|
|
20
|
+
def ==(other)
|
|
21
|
+
if self.class.attribute_names.include?('id')
|
|
22
|
+
if other.is_a?(::Numeric)
|
|
23
|
+
id == other
|
|
24
|
+
elsif other.class == self.class
|
|
25
|
+
id == other.id
|
|
26
|
+
else
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
self.inspect == other.inspect
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
##
|
|
35
|
+
# Compares by code, name, or to_s depending on if the code or name attributes are present.
|
|
36
|
+
def <=>(other)
|
|
37
|
+
m = self.class.default_sort_method
|
|
38
|
+
my_val = send(m)
|
|
39
|
+
|
|
40
|
+
# other can be a string or a model of the same type as this model.
|
|
41
|
+
other_val =
|
|
42
|
+
if other.is_a?(::String)
|
|
43
|
+
other
|
|
44
|
+
elsif other.class == self.class
|
|
45
|
+
other.send(m)
|
|
46
|
+
else
|
|
47
|
+
nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
my_val <=> other_val
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# Additional static methods for the ActiveRecord::Base class.
|
|
55
|
+
module ClassMethods
|
|
56
|
+
|
|
57
|
+
##
|
|
58
|
+
# Gets the default sort method for this model.
|
|
59
|
+
#
|
|
60
|
+
# In order of preference this will be 'code', 'name', or 'to_s'.
|
|
61
|
+
#
|
|
62
|
+
# Specifying a search_attribute before using this method will change this behavior.
|
|
63
|
+
#
|
|
64
|
+
# class MyModel
|
|
65
|
+
# attr_accessor :id, :name, :employee_id
|
|
66
|
+
# end
|
|
67
|
+
# MyModel.default_sort_method # 'name'
|
|
68
|
+
#
|
|
69
|
+
# class MyModel
|
|
70
|
+
# attr_accessor :id, :name, :employee_id
|
|
71
|
+
# search_attribute :employee_id
|
|
72
|
+
# end
|
|
73
|
+
# MyModel.default_sort_method # 'employee_id'
|
|
74
|
+
def default_sort_method
|
|
75
|
+
@default_sort_method ||= search_attributes.find{|a| attribute_names.include?(a)} || 'to_s'
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
##
|
|
79
|
+
# Specifies an attribute to search in the get_id, get, and [] methods.
|
|
80
|
+
#
|
|
81
|
+
# The default attributes to search are 'code' and 'name'. If you specify
|
|
82
|
+
# an additional attribute it will be prefixed to the list. This affects
|
|
83
|
+
# sorting behavior, but not necessarily the search behavior since if the 'code'
|
|
84
|
+
# or 'name' attributes are also present, they will be searched as well.
|
|
85
|
+
#
|
|
86
|
+
# class MyModel
|
|
87
|
+
# attr_accessor :id, :name, :employee_id
|
|
88
|
+
# search_attribute :employee_id
|
|
89
|
+
# end
|
|
90
|
+
def search_attribute(attrib)
|
|
91
|
+
unless attrib.blank?
|
|
92
|
+
attrib = attrib.to_s.strip
|
|
93
|
+
search_attributes.insert(0, attrib) unless search_attributes.include?(attrib)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
##
|
|
98
|
+
# Gets the ID(s) based on the specified value.
|
|
99
|
+
#
|
|
100
|
+
# If a valid model is provided, then the :id attribute is returned.
|
|
101
|
+
#
|
|
102
|
+
# An integer simply gets returned. No validation is done to ensure it is a valid ID.
|
|
103
|
+
# A string representing an integer gets converted and returned. No validation is done.
|
|
104
|
+
# get_id(1234) => 1234
|
|
105
|
+
# get_id('1234') => 1234
|
|
106
|
+
#
|
|
107
|
+
# All further searches are against lowercased :code or :name attributes if either is a valid attribute.
|
|
108
|
+
# You can use the search_attribute method to add another attribute to compare against.
|
|
109
|
+
#
|
|
110
|
+
# A symbol is converted to a string and a humanized string.
|
|
111
|
+
# get_id(:one_two_three) => searches for 'one_two_three' or 'one two three'.
|
|
112
|
+
#
|
|
113
|
+
# Strings are lowercased and compared against lowercased :code or :name if either of those is a valid attribute.
|
|
114
|
+
# get_id('Alpha Bravo') => searches for 'alpha bravo'
|
|
115
|
+
#
|
|
116
|
+
# If a string begins with a # and contains only numbers after that, then it will allow you to search for a
|
|
117
|
+
# non-ID field that only contains numbers. The value is searched as both the supplied value and only the numeric
|
|
118
|
+
# digits.
|
|
119
|
+
#
|
|
120
|
+
# get_id('#1234') => searches for '#1234' or '1234'
|
|
121
|
+
#
|
|
122
|
+
# Arrays are mapped as above.
|
|
123
|
+
#
|
|
124
|
+
# In all cases, if one result is found that value is returned, if more than one is found then an array is returned,
|
|
125
|
+
# and if no results are found, nil is returned. If the model does not include an :id attributes, then nil will
|
|
126
|
+
# always be returned because there can be no valid results.
|
|
127
|
+
#
|
|
128
|
+
# # Assuming this data set:
|
|
129
|
+
# # ID | NAME
|
|
130
|
+
# # -------|--------------------
|
|
131
|
+
# # 1 | Juliet
|
|
132
|
+
# # 2 | Romeo
|
|
133
|
+
# # 3 | 4321
|
|
134
|
+
# # 4 | 1234
|
|
135
|
+
#
|
|
136
|
+
# get_id(1,3,5,7,'Romeo','#1234') # returns [ 1, 3, 5, 7, 2, 4 ]
|
|
137
|
+
# # 1, 3, 5, & 7 are not verified, but :name is searched for "romeo", "#1234", and "1234" to add 2 & 4.
|
|
138
|
+
#
|
|
139
|
+
# get_id('#4321') # returns 3 since there is only one valid result.
|
|
140
|
+
#
|
|
141
|
+
def get_id(*value)
|
|
142
|
+
return nil if value.blank?
|
|
143
|
+
return nil unless attribute_names.include?('id')
|
|
144
|
+
|
|
145
|
+
value = value.first if value.count == 1
|
|
146
|
+
|
|
147
|
+
return value.map{|v| get_id(v)} if value.is_a?(::Array)
|
|
148
|
+
|
|
149
|
+
return value.id if value.class == self
|
|
150
|
+
return value if value.is_a?(::Integer)
|
|
151
|
+
return value.to_i if value.to_s =~ /\A\d+\z/
|
|
152
|
+
|
|
153
|
+
result = search_for(value).order(:id).pluck(:id).to_a
|
|
154
|
+
|
|
155
|
+
return nil if result.blank?
|
|
156
|
+
return result.first if result.count == 1
|
|
157
|
+
|
|
158
|
+
result
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
##
|
|
162
|
+
# Gets one or more items based on the value.
|
|
163
|
+
#
|
|
164
|
+
# Always returns an array of items or nil if no results were found.
|
|
165
|
+
#
|
|
166
|
+
# See #get_id for how the value is processed. The only difference is
|
|
167
|
+
# numeric IDs must be valid for the models to be returned.
|
|
168
|
+
#
|
|
169
|
+
# # Assuming this data set:
|
|
170
|
+
# # ID | NAME
|
|
171
|
+
# # -------|--------------------
|
|
172
|
+
# # 1 | Juliet
|
|
173
|
+
# # 2 | Romeo
|
|
174
|
+
# # 3 | 4321
|
|
175
|
+
# # 4 | 1234
|
|
176
|
+
#
|
|
177
|
+
# get(5) # returns nil
|
|
178
|
+
# get(1,3,5,7) # returns [ { 1 => Juliet }, { 3 => 4321 } ]
|
|
179
|
+
# get('Romeo') # returns [ { 2 => Romeo } ]
|
|
180
|
+
# get('#1234') # returns [ { 4 => 1234 } ]
|
|
181
|
+
#
|
|
182
|
+
def get(*value)
|
|
183
|
+
return nil if value.blank?
|
|
184
|
+
|
|
185
|
+
value = value.first if value.count == 1
|
|
186
|
+
|
|
187
|
+
return value if value.class == self
|
|
188
|
+
|
|
189
|
+
result = search_for(value)
|
|
190
|
+
first_sort = search_attributes.find{|a| attribute_names.include?(a)}
|
|
191
|
+
if first_sort
|
|
192
|
+
result = result.order(first_sort, :id)
|
|
193
|
+
else
|
|
194
|
+
result = result.order(:id)
|
|
195
|
+
end
|
|
196
|
+
result = result.to_a
|
|
197
|
+
return nil if result.blank?
|
|
198
|
+
result
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
##
|
|
202
|
+
# Gets one item based on the value.
|
|
203
|
+
#
|
|
204
|
+
# Always returns the first item found or nil if there were no matches.
|
|
205
|
+
#
|
|
206
|
+
# See #get_id for how the value is processed. The only difference is
|
|
207
|
+
# numeric IDs must be valid for the model to be returned.
|
|
208
|
+
#
|
|
209
|
+
# # Assuming this data set:
|
|
210
|
+
# # ID | NAME
|
|
211
|
+
# # -------|--------------------
|
|
212
|
+
# # 1 | Juliet
|
|
213
|
+
# # 2 | Romeo
|
|
214
|
+
# # 3 | 4321
|
|
215
|
+
# # 4 | 1234
|
|
216
|
+
#
|
|
217
|
+
# [5] # returns nil
|
|
218
|
+
# [1,3,5,7] # returns { 1 => Juliet }
|
|
219
|
+
# ['Romeo'] # returns { 2 => Romeo }
|
|
220
|
+
# ['#1234'] # returns { 4 => 1234 }
|
|
221
|
+
#
|
|
222
|
+
def [](*value)
|
|
223
|
+
get(*value)&.first
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
private
|
|
227
|
+
|
|
228
|
+
def search_attributes
|
|
229
|
+
@search_attributes ||= %w(code name)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def search_for(values)
|
|
233
|
+
# make sure we have an array that we can safely modify.
|
|
234
|
+
values = values.is_a?(::Array) ? values.dup : [ values ]
|
|
235
|
+
values.reject!{|v| v.blank?}
|
|
236
|
+
values.flatten!
|
|
237
|
+
|
|
238
|
+
# return a query that will return no records.
|
|
239
|
+
return self.where('(1 = 0)') if values.blank?
|
|
240
|
+
|
|
241
|
+
# extract potential IDs.
|
|
242
|
+
ids = values
|
|
243
|
+
.select{|v| !v.is_a?(::Symbol) && v.to_s =~ /\A\d+\z/}
|
|
244
|
+
.map{|v| v.to_i}
|
|
245
|
+
|
|
246
|
+
# convert models to IDs to force reloading them.
|
|
247
|
+
ids += values
|
|
248
|
+
.select{|v| v.class == self}
|
|
249
|
+
.map{|v| v.id}
|
|
250
|
+
|
|
251
|
+
# only unique IDs are kept.
|
|
252
|
+
ids.uniq!
|
|
253
|
+
|
|
254
|
+
# and then extract string/symbol values for further searching.
|
|
255
|
+
# purely numeric values and blank values are discarded.
|
|
256
|
+
values = values
|
|
257
|
+
.select{|v| (v.is_a?(::String) && !v.blank? && !(v =~ /\A\d+\z/)) || (v.is_a?(::Symbol) && !v.to_s.blank?)}
|
|
258
|
+
.map{|v| (v.is_a?(::String) && v =~ /\A#\d+\z/) ? [ v, v[1..-1] ] : v}
|
|
259
|
+
.map{|v| v.is_a?(::Symbol) ? [ v.to_s.downcase, v.to_s.humanize.downcase ] : v.to_s.humanize.downcase}
|
|
260
|
+
.flatten
|
|
261
|
+
|
|
262
|
+
# only unique values are kept.
|
|
263
|
+
values.uniq!
|
|
264
|
+
|
|
265
|
+
# get the attributes to search.
|
|
266
|
+
attribs = search_attributes
|
|
267
|
+
.select{|attr| attribute_names.include?(attr)}
|
|
268
|
+
.map{|a| a.to_s.gsub("'", "''").gsub('"','""') }
|
|
269
|
+
|
|
270
|
+
# do a sanity check.
|
|
271
|
+
raise 'No valid values to search for.' if ids.blank? && values.blank?
|
|
272
|
+
raise 'No ID attribute to search.' unless ids.blank? || attribute_names.include?('id')
|
|
273
|
+
raise 'No attributes to search.' unless values.blank? || attribs.any?
|
|
274
|
+
|
|
275
|
+
filters = []
|
|
276
|
+
filter_values = []
|
|
277
|
+
tbl = table_name.to_s.gsub("'", "''").gsub('"','""')
|
|
278
|
+
|
|
279
|
+
# include the ID filters.
|
|
280
|
+
ids.each do |id|
|
|
281
|
+
filters << "(\"#{tbl}\".\"id\" = ?)"
|
|
282
|
+
filter_values << id
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# include the value filters.
|
|
286
|
+
values.each do |value|
|
|
287
|
+
attribs.each do |attr|
|
|
288
|
+
filters << "(LOWER(\"#{tbl}\".\"#{attr}\") = ?)"
|
|
289
|
+
filter_values << value
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
filters = filters.join(' OR ')
|
|
294
|
+
|
|
295
|
+
self.where(filters, *filter_values)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def self.included(base)
|
|
301
|
+
base.class_eval do
|
|
302
|
+
extend ClassMethods
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
ActiveRecord::Base.include Incline::Extensions::ActiveRecordBase
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
require 'cgi/util'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'rails'
|
|
5
|
+
|
|
6
|
+
module Incline::Extensions
|
|
7
|
+
##
|
|
8
|
+
# Adds some informational methods to the Application class.
|
|
9
|
+
module Application
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Is the rails server running?
|
|
13
|
+
def running?
|
|
14
|
+
path = File.join(Rails.root, 'tmp/pids/server.pid')
|
|
15
|
+
pid = File.exist?(path) ? File.read(path).to_i : -1
|
|
16
|
+
server_running = true
|
|
17
|
+
begin
|
|
18
|
+
Process.getpgid pid
|
|
19
|
+
rescue Errno::ESRCH
|
|
20
|
+
server_running = false
|
|
21
|
+
end
|
|
22
|
+
server_running
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
# Gets the application name.
|
|
27
|
+
#
|
|
28
|
+
# You should override this method in your +application.rb+ file to return the appropriate value.
|
|
29
|
+
def app_name
|
|
30
|
+
default_notify :app_name
|
|
31
|
+
'Incline'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
##
|
|
35
|
+
# Gets the application instance name.
|
|
36
|
+
#
|
|
37
|
+
# This can be set by creating a +config/instance.yml+ configuration file and setting the 'name' property.
|
|
38
|
+
# The instance name is used to create unique cookies for each instance of an application.
|
|
39
|
+
# The default instance name is 'default'.
|
|
40
|
+
def app_instance_name
|
|
41
|
+
@app_instance_name ||=
|
|
42
|
+
begin
|
|
43
|
+
yaml = Rails.root.join('config','instance.yml')
|
|
44
|
+
if File.exist?(yaml)
|
|
45
|
+
yaml = (YAML.load_file(yaml) || {}).symbolize_keys
|
|
46
|
+
yaml[:name].blank? ? 'default' : yaml[:name]
|
|
47
|
+
else
|
|
48
|
+
'default'
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# Gets the application version.
|
|
55
|
+
#
|
|
56
|
+
# You should override this method in your +application.rb+ file to return the appropriate value.
|
|
57
|
+
def app_version
|
|
58
|
+
default_notify :app_version
|
|
59
|
+
'0.0.1'
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
##
|
|
63
|
+
# Gets the company owning the copyright to the application.
|
|
64
|
+
#
|
|
65
|
+
# You should override this method in your +application.rb+ file to return the appropriate value.
|
|
66
|
+
def app_company
|
|
67
|
+
default_notify :app_company
|
|
68
|
+
'BarkerEST'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
##
|
|
72
|
+
# Gets the year of copyright ownership for the company.
|
|
73
|
+
#
|
|
74
|
+
# Defaults to the current year (at the time of execution).
|
|
75
|
+
def app_copyright_year
|
|
76
|
+
Time.now.year.to_s
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
##
|
|
80
|
+
# Gets the application name and version.
|
|
81
|
+
def app_info
|
|
82
|
+
"#{app_name} v#{app_version}"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
##
|
|
86
|
+
# Gets the copyright statement for this application.
|
|
87
|
+
def app_copyright(html = true)
|
|
88
|
+
if html
|
|
89
|
+
"Copyright © #{CGI::escapeHTML app_copyright_year} #{CGI::escapeHTML app_company}".html_safe
|
|
90
|
+
else
|
|
91
|
+
"Copyright (C) #{app_copyright_year} #{app_company}"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
##
|
|
96
|
+
# Is a restart currently pending.
|
|
97
|
+
def restart_pending?
|
|
98
|
+
return false unless File.exist?(restart_file)
|
|
99
|
+
request_time = File.mtime(restart_file)
|
|
100
|
+
request_time > Incline.start_time
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
##
|
|
104
|
+
# Updates the restart file to indicate we want to restart the web app.
|
|
105
|
+
def request_restart!
|
|
106
|
+
Incline::Log::info 'Requesting an application restart.'
|
|
107
|
+
FileUtils.touch restart_file
|
|
108
|
+
File.mtime restart_file
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
##
|
|
112
|
+
# Generates a cookie name using the application name and instance name.
|
|
113
|
+
def cookie_name(cookie)
|
|
114
|
+
"_incline_#{app_name.downcase.scan(/[a-z0-9]+/).join('_')}_#{app_instance_name.downcase.scan(/[a-z0-9]+/).join('_')}_#{cookie}"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
private
|
|
119
|
+
|
|
120
|
+
def default_notify(property)
|
|
121
|
+
@default_notify ||= {}
|
|
122
|
+
@default_notify[property] ||= 0
|
|
123
|
+
if @default_notify[property] == 0
|
|
124
|
+
@default_notify[property] = 1
|
|
125
|
+
Incline::Log::warn "Default \"#{property}\" is in use. Please define \"#{property}\" in your \"application.rb\" file."
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def restart_file
|
|
130
|
+
@restart_file ||= "#{self.config.root}/tmp/restart.txt"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
Rails::Application.include Incline::Extensions::Application
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'rails'
|
|
2
|
+
|
|
3
|
+
module Incline::Extensions
|
|
4
|
+
##
|
|
5
|
+
# Creates a default database configuration to use when config/database.yml is not present.
|
|
6
|
+
module ApplicationConfiguration
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# Override the +database_configuration+ method to return something in development mode if
|
|
10
|
+
# the +config/database.yml+ file is missing.
|
|
11
|
+
#
|
|
12
|
+
# A warning will be logged if the default configuration is used. In production mode, an
|
|
13
|
+
# exception will be bubbled up.
|
|
14
|
+
#
|
|
15
|
+
# The default configuration for test and development environments is to use a sqlite
|
|
16
|
+
# database in the db folder using the environment name (eg - db/development.sqlite).
|
|
17
|
+
#
|
|
18
|
+
# The primary purpose of this is to allow +rake+ and +rails+ actions that may not depend on the
|
|
19
|
+
# database configuration or may actually be used to generate the configuration file.
|
|
20
|
+
def self.included(base) #:nodoc:
|
|
21
|
+
base.class_eval do
|
|
22
|
+
alias :incline_appconfig_original_database_configuration :database_configuration
|
|
23
|
+
|
|
24
|
+
def database_configuration
|
|
25
|
+
begin
|
|
26
|
+
incline_appconfig_original_database_configuration
|
|
27
|
+
rescue
|
|
28
|
+
raise unless $!.inspect.include?('No such file -') && (!Rails.env.production?)
|
|
29
|
+
|
|
30
|
+
default = {
|
|
31
|
+
'adapter' => 'sqlite3',
|
|
32
|
+
'pool' => 5,
|
|
33
|
+
'timeout' => 5000
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
Incline::Log::warn "Providing default database configuration for #{Rails.env} environment."
|
|
37
|
+
|
|
38
|
+
{
|
|
39
|
+
'test' => default.merge('database' => 'db/test.sqlite'),
|
|
40
|
+
'development' => default.merge('database' => 'db/development.sqlite')
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
Rails::Application::Configuration.include Incline::Extensions::ApplicationConfiguration
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'active_record'
|
|
2
|
+
|
|
3
|
+
module Incline::Extensions
|
|
4
|
+
##
|
|
5
|
+
# Adds some extra functionality to database connections.
|
|
6
|
+
module ConnectionAdapter
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# Searches the database to determine if an object with the specified name exists.
|
|
10
|
+
def object_exists?(object_name)
|
|
11
|
+
safe_name = "'#{object_name.gsub('\'','\'\'')}'"
|
|
12
|
+
|
|
13
|
+
sql =
|
|
14
|
+
case self.class.name
|
|
15
|
+
when 'ActiveRecord::ConnectionAdapters::SQLServerAdapter'
|
|
16
|
+
# use sysobjects table.
|
|
17
|
+
"SELECT COUNT(*) AS \"one\" FROM \"sysobjects\" WHERE \"name\"=#{safe_name}"
|
|
18
|
+
when 'ActiveRecord::ConnectionAdapters::SQLite3Adapter'
|
|
19
|
+
# use sqlite_master table.
|
|
20
|
+
"SELECT COUNT(*) AS \"one\" FROM \"sqlite_master\" WHERE (\"type\"='table' OR \"type\"='view') AND (\"name\"=#{safe_name})"
|
|
21
|
+
else
|
|
22
|
+
# query the information_schema TABLES and ROUTINES views.
|
|
23
|
+
"SELECT SUM(Z.\"one\") AS \"one\" FROM (SELECT COUNT(*) AS \"one\" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=#{safe_name} UNION SELECT COUNT(*) AS \"one\" FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME=#{safe_name}) AS Z"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
result = exec_query(sql).first
|
|
27
|
+
|
|
28
|
+
result && result['one'] >= 1
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# Executes a stored procedure.
|
|
33
|
+
#
|
|
34
|
+
# For MS SQL Server, this will return the return value from the procedure.
|
|
35
|
+
# For other providers, this is the same as +execute+.
|
|
36
|
+
def exec_sp(stmt)
|
|
37
|
+
case self.class.name
|
|
38
|
+
when 'ActiveRecord::ConnectionAdapters::SQLServerAdapter'
|
|
39
|
+
rex = /^exec(?:ute)?\s+[\["]?(?<PROC>[a-z][a-z0-9_]*)[\]"]?(?<ARGS>\s.*)?$/i
|
|
40
|
+
match = rex.match(stmt)
|
|
41
|
+
if match
|
|
42
|
+
exec_query("DECLARE @SP__RET INTEGER; EXECUTE @SP__RET=[#{match['PROC']}]#{match['ARGS']}; SELECT @SP__RET AS [RET]").first['RET']
|
|
43
|
+
else
|
|
44
|
+
execute stmt
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
execute stmt
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.include Incline::Extensions::ConnectionAdapter
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require 'incline/date_time_formats'
|
|
2
|
+
require 'incline/extensions/time_zone_converter'
|
|
3
|
+
require 'active_record'
|
|
4
|
+
|
|
5
|
+
module Incline::Extensions
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# Patches the ActiveRecord DateTime value to accept more date formats.
|
|
9
|
+
#
|
|
10
|
+
# Specifically this will allow ActiveRecord models to receive dates in US format or ISO format.
|
|
11
|
+
module DateTimeValue
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# Patches the ActiveRecord DateTime value type.
|
|
15
|
+
def self.included(base)
|
|
16
|
+
base.class_eval do
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
undef cast_value
|
|
21
|
+
|
|
22
|
+
def cast_value(string)
|
|
23
|
+
return nil if string.blank?
|
|
24
|
+
return string if string.is_a?(::Time)
|
|
25
|
+
|
|
26
|
+
if string.is_a?(::String)
|
|
27
|
+
|
|
28
|
+
begin
|
|
29
|
+
# if it matches either of our formats, we can try using it.
|
|
30
|
+
if (match = (Incline::DateTimeFormats::US_DATE_FORMAT.match(string) || Incline::DateTimeFormats::ALMOST_ISO_DATE_FORMAT.match(string)))
|
|
31
|
+
|
|
32
|
+
year = match['YEAR'].to_s.to_i
|
|
33
|
+
year += 2000 if year < 50
|
|
34
|
+
year += 1900 if year < 100
|
|
35
|
+
month = match['MONTH'].to_s.to_i
|
|
36
|
+
mday = match['DAY'].to_s.to_i
|
|
37
|
+
|
|
38
|
+
# ensure the date portion is valid.
|
|
39
|
+
dt =
|
|
40
|
+
begin
|
|
41
|
+
Time.utc(year, month, mday)
|
|
42
|
+
rescue
|
|
43
|
+
raise "Invalid date (#{$!.message})."
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
raise 'Invalid date (day of month is invalid for month).' unless dt.year == year && dt.month == month && dt.mday == mday
|
|
47
|
+
|
|
48
|
+
hour = match['HOUR'].to_s.to_i
|
|
49
|
+
minute = match['MINUTE'].to_s.to_i
|
|
50
|
+
second = match['SECOND'].to_s.to_i
|
|
51
|
+
|
|
52
|
+
# make sure the fraction is 6 chars in length, then convert to microseconds.
|
|
53
|
+
micros = match['FRACTION'].to_s[0...6].ljust(6,'0').to_i
|
|
54
|
+
|
|
55
|
+
if match.names.include?('AMPM')
|
|
56
|
+
if match['AMPM'].to_s.upcase == 'P' && hour < 12
|
|
57
|
+
hour += 12
|
|
58
|
+
elsif match['AMPM'].to_s.upcase == 'A' && hour == 12
|
|
59
|
+
hour = 0
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
raise 'Invalid time (hour must be 0 to 24).' unless (0..24) === hour
|
|
64
|
+
raise 'Invalid time (minute must be 0 to 59).' unless (0...60) === minute
|
|
65
|
+
raise 'Invalid time (second must be 0 to 59).' unless (0...60) === second
|
|
66
|
+
raise 'Invalid time (minute and second must be 0 if hour is 24).' if hour == 24 && (minute != 0 || second != 0)
|
|
67
|
+
|
|
68
|
+
if hour == 24
|
|
69
|
+
dt += 86400
|
|
70
|
+
year = dt.year
|
|
71
|
+
month = dt.month
|
|
72
|
+
mday = dt.mday
|
|
73
|
+
hour = 0
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# compute the tz offset in seconds.
|
|
77
|
+
offset =
|
|
78
|
+
if match.names.include?('TZ')
|
|
79
|
+
if match['TZ']
|
|
80
|
+
tz = match['TZ'].to_s.gsub(':','').upcase
|
|
81
|
+
if %w(Z +0000 -0000).include?(tz)
|
|
82
|
+
0
|
|
83
|
+
else
|
|
84
|
+
(tz[0] == '-' ? -1 : 1) * ((tz[1..2].to_i * 3600) + (tz[3..4].to_i * 60))
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
nil
|
|
88
|
+
end
|
|
89
|
+
else
|
|
90
|
+
nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# use the new_time method to honor the ActiveRecord::Base.default_timezone
|
|
94
|
+
new_time(year, month, mday, hour, minute, second, micros, offset)
|
|
95
|
+
else
|
|
96
|
+
# use the fallback if it doesn't match our formats.
|
|
97
|
+
fallback_string_to_time(string)
|
|
98
|
+
end
|
|
99
|
+
rescue
|
|
100
|
+
Incline::Log::warn "Failed to parse #{string.inspect}: #{$!.message}"
|
|
101
|
+
nil
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
elsif string.respond_to?(:to_time)
|
|
105
|
+
begin
|
|
106
|
+
string.to_time
|
|
107
|
+
rescue
|
|
108
|
+
Incline::Log::warn "Failed to convert #{string.inspect} to time: #{$!.message}"
|
|
109
|
+
nil
|
|
110
|
+
end
|
|
111
|
+
else
|
|
112
|
+
nil
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
ActiveRecord::Type::DateTime.include Incline::Extensions::DateTimeValue
|
|
123
|
+
|