syncwise_api 0.0.1

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 (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +1 -0
  9. data/lib/syncwise_api/client.rb +47 -0
  10. data/lib/syncwise_api/errors.rb +93 -0
  11. data/lib/syncwise_api/ext/core_ext.rb +176 -0
  12. data/lib/syncwise_api/ext/inflections.rb +66 -0
  13. data/lib/syncwise_api/ext/inflector/inflections.rb +177 -0
  14. data/lib/syncwise_api/ext/inflector_methods.rb +62 -0
  15. data/lib/syncwise_api/ext/string_encoding.rb +12 -0
  16. data/lib/syncwise_api/mixins/mixins.rb +1 -0
  17. data/lib/syncwise_api/mixins/request_builder.rb +23 -0
  18. data/lib/syncwise_api/mixins/request_sender.rb +11 -0
  19. data/lib/syncwise_api/mixins/request_signer.rb +20 -0
  20. data/lib/syncwise_api/requests/V1_0/assign_device_create.rb +19 -0
  21. data/lib/syncwise_api/requests/V1_0/base.rb +115 -0
  22. data/lib/syncwise_api/requests/V1_0/device_details.rb +19 -0
  23. data/lib/syncwise_api/requests/V1_0/device_list.rb +19 -0
  24. data/lib/syncwise_api/requests/V1_0/device_settings_details.rb +19 -0
  25. data/lib/syncwise_api/requests/V1_0/device_settings_edit.rb +19 -0
  26. data/lib/syncwise_api/requests/V1_0/device_subscribe.rb +19 -0
  27. data/lib/syncwise_api/requests/V1_0/device_unsubscribe.rb +19 -0
  28. data/lib/syncwise_api/requests/V1_0/driver_speed_report.rb +19 -0
  29. data/lib/syncwise_api/requests/V1_0/obd_vehicle_details.rb +19 -0
  30. data/lib/syncwise_api/requests/V1_0/trip_event_details.rb +19 -0
  31. data/lib/syncwise_api/requests/V1_0/user_login.rb +26 -0
  32. data/lib/syncwise_api/requests/V1_0/user_subscribe_settings_details.rb +19 -0
  33. data/lib/syncwise_api/requests/V1_0/vehicle_gauge_information.rb +19 -0
  34. data/lib/syncwise_api/requests/V1_0/vehicle_idling_history.rb +19 -0
  35. data/lib/syncwise_api/requests/requests.rb +2 -0
  36. data/lib/syncwise_api/responses/V1_0/base.rb +35 -0
  37. data/lib/syncwise_api/responses/V1_0/standard.rb +9 -0
  38. data/lib/syncwise_api/responses/responses.rb +1 -0
  39. data/lib/syncwise_api/service_utils/crypto/hmac_sha256.rb +15 -0
  40. data/lib/syncwise_api/service_utils/encoders/base64.rb +16 -0
  41. data/lib/syncwise_api/service_utils/encoders/json.rb +21 -0
  42. data/lib/syncwise_api/service_utils/http.rb +34 -0
  43. data/lib/syncwise_api/service_utils/parsers/json.rb +55 -0
  44. data/lib/syncwise_api/service_utils/service_utils.rb +2 -0
  45. data/lib/syncwise_api/service_utils/time_stamper.rb +13 -0
  46. data/lib/syncwise_api/version.rb +3 -0
  47. data/lib/syncwise_api.rb +30 -0
  48. data/syncwise_api.gemspec +27 -0
  49. data/tester.rb +10 -0
  50. metadata +162 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d5ab37738b62b0ea99540366cc22ebe5352a6758
4
+ data.tar.gz: 50b3e3a806577539e51e8dbb7c0d7d64bea67530
5
+ SHA512:
6
+ metadata.gz: 460840491191c2bcb26381782446c568ac45126a24a4f2c1a24c80e401b9b19d0874c204706c64007ea7a2504eedfacfc35e18d0a3cd0c824cb31575bad56e61
7
+ data.tar.gz: 1a4992ebb5800beb11b5b12c9a00f86c4e759ec68bea7cbe1f0e9208957ef276d4a8325b62e34fc957f84a82caef384d05e9e7c69a64e095e79e423ecef6a2f1
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ bin/
19
+ .idea/
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ syncwise_api
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.0.0-p0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in syncwise_api.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Brendten Eickstaedt
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # SyncwiseApi
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'syncwise_api'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install syncwise_api
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,47 @@
1
+ module SyncwiseApi
2
+ class Client
3
+
4
+ def initialize(username, password)
5
+ @username = username
6
+ @password = password
7
+ login
8
+ end
9
+
10
+ def make_request(action_code, params)
11
+ if action_code == :user_login
12
+ puts 'Login is done automatically when a new Client is created. Ignoring this call.'
13
+ else
14
+ action_code = action_code.camelize
15
+ if SyncwiseApi::Requests::V1_0.const_defined?(action_code)
16
+ params[:'Action Code'] = action_code
17
+ params[:'API Key'] = @username
18
+ params[:secretKey] = @secret_key
19
+ params[:accountId] = @account_id
20
+ request_class = SyncwiseApi::Requests::V1_0.const_get(action_code)
21
+ request = request_class.new(params)
22
+ response = request.send_request
23
+ else
24
+ puts 'Sorry, that\'s not a valid request type.'
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def login
32
+ begin
33
+ request = SyncwiseApi::Requests::V1_0::UserLogin.new({:'API Key' => @username, :password => @password, :secretKey => '', :accountId => ''})
34
+ response = request.send_request
35
+ if response.valid?
36
+ @secret_key = response.body_hash[:secret_key]
37
+ @account_id = response.body_hash[:account_id]
38
+ else
39
+ fail SyncwiseApi::Errors::ApiErrorCode.new(response, request, response.header_hash, response.body_hash)
40
+ end
41
+ rescue => e
42
+ SyncwiseApi::LOGGER.error e
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,93 @@
1
+ module SyncwiseApi
2
+ module Errors
3
+
4
+ class SyncwiseError < StandardError
5
+
6
+ end
7
+
8
+ class MissingInstanceVariable < SyncwiseError
9
+ def initialize(variable, mixin, receiver)
10
+ @variable = variable
11
+ @mixin = mixin
12
+ @receiver_inspect = receiver.inspect
13
+ super("Mixin #{@mixin} tried to use undefined instance variable #{@variable} in #{@receiver_inspect}")
14
+ end
15
+
16
+ attr_reader :variable, :mixin, :receiver_inspect
17
+ end
18
+
19
+ class InvalidParameters < SyncwiseError
20
+ def initialize(request_type, passed_params, required_params)
21
+ @request_type = request_type
22
+ @passed_params = passed_params
23
+ @required_params = required_params
24
+ super("#{@request_type} was called with params #{@passed_params}, but requires params #{@required_params}")
25
+ end
26
+
27
+ attr_reader :request_type, :passed_params, :required_params
28
+ end
29
+
30
+ class JSONParseError < SyncwiseError
31
+ def initialize(error)
32
+ @error = error
33
+ super("Error parsing JSON: #{@error}")
34
+ end
35
+
36
+ attr_reader :error
37
+ end
38
+
39
+ class JSONEncodeError < SyncwiseError
40
+ def initialize(object)
41
+ @object = object
42
+ super("Error encoding object into JSON. Object: #{@object.inspect}")
43
+ end
44
+
45
+ attr_reader :object
46
+ end
47
+
48
+ class HttpError < SyncwiseError
49
+ def initialize(error, request)
50
+ @error = error
51
+ @request = request
52
+ super("Http Error when trying to make request. Object: #{@error.inspect}, request: #{@request}")
53
+ end
54
+
55
+ attr_reader :error, :request
56
+ end
57
+
58
+ class SyncwiseApi::Errors::EmptyResponseBody < SyncwiseError
59
+ def initialize(resp, request, header)
60
+ @resp = resp
61
+ @request = request
62
+ @header = header
63
+ super("Api call returned with empty body. Response: #{@resp}, request: #{@request}, header: #{@header}")
64
+ end
65
+
66
+ attr_reader :resp, :request, :header
67
+ end
68
+
69
+ class SyncwiseApi::Errors::InvalidContentType < SyncwiseError
70
+ def initialize(resp, request, header)
71
+ @resp = resp
72
+ @request = request
73
+ @header = header
74
+ super("Api call returned an invalid Content-Type. Response: #{@resp}, request: #{@request}, header: #{@header}")
75
+ end
76
+
77
+ attr_reader :resp, :request, :header
78
+ end
79
+
80
+ class SyncwiseApi::Errors::ApiErrorCode < SyncwiseError
81
+ def initialize(resp, request, header, body)
82
+ @resp = resp
83
+ @request = request
84
+ @header = header
85
+ @body = body
86
+ super("Api call returned a Syncwise Error Code. Response: #{@resp}, request: #{@request}, header: #{@header}, body: #{@body}")
87
+ end
88
+
89
+ attr_reader :resp, :request, :header, :body
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,176 @@
1
+ # encoding: utf-8
2
+ require_relative 'string_encoding'
3
+ require_relative 'inflector_methods'
4
+
5
+ # so there are some things from Rails I love, and have a hard time living without when using PORO.
6
+ # i'm adding them back here. thanks, Rails Core team ;)
7
+ class Hash
8
+ def deep_symbolize_keys
9
+ result = {}
10
+ each do |key, value|
11
+ result[(key.underscore.dehumanize.to_sym rescue key)] = value.is_a?(Hash) ? value.deep_symbolize_keys : value
12
+ end
13
+ result
14
+ end
15
+
16
+ alias_method :symbolize_keys, :deep_symbolize_keys
17
+ end
18
+
19
+ class Object
20
+ # An object is blank if it's false, empty, or a whitespace string.
21
+ # For example, "", " ", +nil+, [], and {} are all blank.
22
+ #
23
+ # This simplifies:
24
+ #
25
+ # if address.nil? || address.empty?
26
+ #
27
+ # ...to:
28
+ #
29
+ # if address.blank?
30
+ def blank?
31
+ respond_to?(:empty?) ? empty? : !self
32
+ end
33
+
34
+ # An object is present if it's not <tt>blank?</tt>.
35
+ def present?
36
+ !blank?
37
+ end
38
+
39
+ # Returns object if it's <tt>present?</tt> otherwise returns +nil+.
40
+ # <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
41
+ #
42
+ # This is handy for any representation of objects where blank is the same
43
+ # as not present at all. For example, this simplifies a common check for
44
+ # HTTP POST/query parameters:
45
+ #
46
+ # state = params[:state] if params[:state].present?
47
+ # country = params[:country] if params[:country].present?
48
+ # region = state || country || 'US'
49
+ #
50
+ # ...becomes:
51
+ #
52
+ # region = params[:state].presence || params[:country].presence || 'US'
53
+ def presence
54
+ self if present?
55
+ end
56
+
57
+ # Returns just the class name as a String, without namespace/modules
58
+ # For example, this method called on class This::That::AndTheOtherThing will
59
+ # return AndTheOtherThing
60
+ def unqualified_class
61
+ self.class.to_s.split('::').last
62
+ end
63
+ end
64
+
65
+ class NilClass
66
+ # +nil+ is blank:
67
+ #
68
+ # nil.blank? # => true
69
+ #
70
+ def blank?
71
+ true
72
+ end
73
+ end
74
+
75
+ class FalseClass
76
+ # +false+ is blank:
77
+ #
78
+ # false.blank? # => true
79
+ #
80
+ def blank?
81
+ true
82
+ end
83
+ end
84
+
85
+ class TrueClass
86
+ # +true+ is not blank:
87
+ #
88
+ # true.blank? # => false
89
+ #
90
+ def blank?
91
+ false
92
+ end
93
+ end
94
+
95
+ class Array
96
+ # An array is blank if it's empty:
97
+ #
98
+ # [].blank? # => true
99
+ # [1,2,3].blank? # => false
100
+ #
101
+ alias_method :blank?, :empty?
102
+ end
103
+
104
+ class Hash
105
+ # A hash is blank if it's empty:
106
+ #
107
+ # {}.blank? # => true
108
+ # {:key => 'value'}.blank? # => false
109
+ #
110
+ alias_method :blank?, :empty?
111
+ end
112
+
113
+ class String
114
+ # 0x3000: fullwidth whitespace
115
+ NON_WHITESPACE_REGEXP = %r![^\s#{[0x3000].pack("U")}]!
116
+
117
+ # A string is blank if it's empty or contains whitespaces only:
118
+ #
119
+ # "".blank? # => true
120
+ # " ".blank? # => true
121
+ # " ".blank? # => true
122
+ # " something here ".blank? # => false
123
+ #
124
+ def blank?
125
+ # 1.8 does not takes [:space:] properly
126
+ if encoding_aware?
127
+ self !~ /[^[:space:]]/
128
+ else
129
+ self !~ NON_WHITESPACE_REGEXP
130
+ end
131
+ end
132
+
133
+ def dehumanize
134
+ SyncwiseApi::Inflector.dehumanize(self)
135
+ end
136
+
137
+ def underscore
138
+ SyncwiseApi::Inflector.underscore(self)
139
+ end
140
+
141
+
142
+ # By default, +camelize+ converts strings to UpperCamelCase. If the argument to camelize
143
+ # is set to <tt>:lower</tt> then camelize produces lowerCamelCase.
144
+ #
145
+ # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
146
+ #
147
+ # "active_record".camelize # => "ActiveRecord"
148
+ # "active_record".camelize(:lower) # => "activeRecord"
149
+ # "active_record/errors".camelize # => "ActiveRecord::Errors"
150
+ # "active_record/errors".camelize(:lower) # => "activeRecord::Errors"
151
+ def camelize(first_letter = :upper)
152
+ case first_letter
153
+ when :upper then SyncwiseApi::Inflector.camelize(self, true)
154
+ when :lower then SyncwiseApi::Inflector.camelize(self, false)
155
+ end
156
+ end
157
+ alias_method :camelcase, :camelize
158
+
159
+ end
160
+
161
+ class Numeric #:nodoc:
162
+ # No number is blank:
163
+ #
164
+ # 1.blank? # => false
165
+ # 0.blank? # => false
166
+ #
167
+ def blank?
168
+ false
169
+ end
170
+ end
171
+
172
+ class Symbol
173
+ def camelize
174
+ self.to_s.camelize
175
+ end
176
+ end
@@ -0,0 +1,66 @@
1
+ # taken lock, stock and 2 smoking barrels from rails / activesupport / lib / active_support / inflections.rb
2
+ # thanks again, rails team!
3
+
4
+ require_relative 'inflector/inflections'
5
+
6
+ module SyncwiseApi
7
+ Inflector.inflections do |inflect|
8
+ inflect.plural(/$/, 's')
9
+ inflect.plural(/s$/i, 's')
10
+ inflect.plural(/(ax|test)is$/i, '\1es')
11
+ inflect.plural(/(octop|vir)us$/i, '\1i')
12
+ inflect.plural(/(octop|vir)i$/i, '\1i')
13
+ inflect.plural(/(alias|status)$/i, '\1es')
14
+ inflect.plural(/(bu)s$/i, '\1ses')
15
+ inflect.plural(/(buffal|tomat)o$/i, '\1oes')
16
+ inflect.plural(/([ti])um$/i, '\1a')
17
+ inflect.plural(/([ti])a$/i, '\1a')
18
+ inflect.plural(/sis$/i, 'ses')
19
+ inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
20
+ inflect.plural(/(hive)$/i, '\1s')
21
+ inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
22
+ inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
23
+ inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
24
+ inflect.plural(/(m|l)ouse$/i, '\1ice')
25
+ inflect.plural(/(m|l)ice$/i, '\1ice')
26
+ inflect.plural(/^(ox)$/i, '\1en')
27
+ inflect.plural(/^(oxen)$/i, '\1')
28
+ inflect.plural(/(quiz)$/i, '\1zes')
29
+
30
+ inflect.singular(/s$/i, '')
31
+ inflect.singular(/(n)ews$/i, '\1ews')
32
+ inflect.singular(/([ti])a$/i, '\1um')
33
+ inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1\2sis')
34
+ inflect.singular(/(^analy)ses$/i, '\1sis')
35
+ inflect.singular(/([^f])ves$/i, '\1fe')
36
+ inflect.singular(/(hive)s$/i, '\1')
37
+ inflect.singular(/(tive)s$/i, '\1')
38
+ inflect.singular(/([lr])ves$/i, '\1f')
39
+ inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
40
+ inflect.singular(/(s)eries$/i, '\1eries')
41
+ inflect.singular(/(m)ovies$/i, '\1ovie')
42
+ inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
43
+ inflect.singular(/(m|l)ice$/i, '\1ouse')
44
+ inflect.singular(/(bus)es$/i, '\1')
45
+ inflect.singular(/(o)es$/i, '\1')
46
+ inflect.singular(/(shoe)s$/i, '\1')
47
+ inflect.singular(/(cris|ax|test)es$/i, '\1is')
48
+ inflect.singular(/(octop|vir)i$/i, '\1us')
49
+ inflect.singular(/(alias|status)es$/i, '\1')
50
+ inflect.singular(/^(ox)en/i, '\1')
51
+ inflect.singular(/(vert|ind)ices$/i, '\1ex')
52
+ inflect.singular(/(matr)ices$/i, '\1ix')
53
+ inflect.singular(/(quiz)zes$/i, '\1')
54
+ inflect.singular(/(database)s$/i, '\1')
55
+
56
+ inflect.irregular('person', 'people')
57
+ inflect.irregular('man', 'men')
58
+ inflect.irregular('child', 'children')
59
+ inflect.irregular('sex', 'sexes')
60
+ inflect.irregular('move', 'moves')
61
+ inflect.irregular('cow', 'kine')
62
+ inflect.irregular('zombie', 'zombies')
63
+
64
+ inflect.uncountable(%w(equipment information rice money species series fish sheep jeans))
65
+ end
66
+ end
@@ -0,0 +1,177 @@
1
+ # taken lock, stock and 2 smoking barrels from rails / activesupport / lib / active_support / inflector / inflections.rb
2
+ # thanks again, rails team!
3
+
4
+ module SyncwiseApi
5
+ module Inflector
6
+ extend self
7
+
8
+ # A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
9
+ # inflection rules. Examples:
10
+ #
11
+ # ActiveSupport::Inflector.inflections do |inflect|
12
+ # inflect.plural /^(ox)$/i, '\1\2en'
13
+ # inflect.singular /^(ox)en/i, '\1'
14
+ #
15
+ # inflect.irregular 'octopus', 'octopi'
16
+ #
17
+ # inflect.uncountable "equipment"
18
+ # end
19
+ #
20
+ # New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
21
+ # pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
22
+ # already have been loaded.
23
+ class Inflections
24
+ def self.instance
25
+ @__instance__ ||= new
26
+ end
27
+
28
+ attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms, :acronym_regex
29
+
30
+ def initialize
31
+ @plurals, @singulars, @uncountables, @humans, @acronyms, @acronym_regex = [], [], [], [], {}, /(?=a)b/
32
+ end
33
+
34
+ # Specifies a new acronym. An acronym must be specified as it will appear in a camelized string. An underscore
35
+ # string that contains the acronym will retain the acronym when passed to `camelize`, `humanize`, or `titleize`.
36
+ # A camelized string that contains the acronym will maintain the acronym when titleized or humanized, and will
37
+ # convert the acronym into a non-delimited single lowercase word when passed to +underscore+.
38
+ #
39
+ # Examples:
40
+ # acronym 'HTML'
41
+ # titleize 'html' #=> 'HTML'
42
+ # camelize 'html' #=> 'HTML'
43
+ # underscore 'MyHTML' #=> 'my_html'
44
+ #
45
+ # The acronym, however, must occur as a delimited unit and not be part of another word for conversions to recognize it:
46
+ #
47
+ # acronym 'HTTP'
48
+ # camelize 'my_http_delimited' #=> 'MyHTTPDelimited'
49
+ # camelize 'https' #=> 'Https', not 'HTTPs'
50
+ # underscore 'HTTPS' #=> 'http_s', not 'https'
51
+ #
52
+ # acronym 'HTTPS'
53
+ # camelize 'https' #=> 'HTTPS'
54
+ # underscore 'HTTPS' #=> 'https'
55
+ #
56
+ # Note: Acronyms that are passed to `pluralize` will no longer be recognized, since the acronym will not occur as
57
+ # a delimited unit in the pluralized result. To work around this, you must specify the pluralized form as an
58
+ # acronym as well:
59
+ #
60
+ # acronym 'API'
61
+ # camelize(pluralize('api')) #=> 'Apis'
62
+ #
63
+ # acronym 'APIs'
64
+ # camelize(pluralize('api')) #=> 'APIs'
65
+ #
66
+ # `acronym` may be used to specify any word that contains an acronym or otherwise needs to maintain a non-standard
67
+ # capitalization. The only restriction is that the word must begin with a capital letter.
68
+ #
69
+ # Examples:
70
+ # acronym 'RESTful'
71
+ # underscore 'RESTful' #=> 'restful'
72
+ # underscore 'RESTfulController' #=> 'restful_controller'
73
+ # titleize 'RESTfulController' #=> 'RESTful Controller'
74
+ # camelize 'restful' #=> 'RESTful'
75
+ # camelize 'restful_controller' #=> 'RESTfulController'
76
+ #
77
+ # acronym 'McDonald'
78
+ # underscore 'McDonald' #=> 'mcdonald'
79
+ # camelize 'mcdonald' #=> 'McDonald'
80
+ def acronym(word)
81
+ @acronyms[word.downcase] = word
82
+ @acronym_regex = /#{@acronyms.values.join("|")}/
83
+ end
84
+
85
+ # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
86
+ # The replacement should always be a string that may include references to the matched data from the rule.
87
+ def plural(rule, replacement)
88
+ @uncountables.delete(rule) if rule.is_a?(String)
89
+ @uncountables.delete(replacement)
90
+ @plurals.insert(0, [rule, replacement])
91
+ end
92
+
93
+ # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
94
+ # The replacement should always be a string that may include references to the matched data from the rule.
95
+ def singular(rule, replacement)
96
+ @uncountables.delete(rule) if rule.is_a?(String)
97
+ @uncountables.delete(replacement)
98
+ @singulars.insert(0, [rule, replacement])
99
+ end
100
+
101
+ # Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
102
+ # for strings, not regular expressions. You simply pass the irregular in singular and plural form.
103
+ #
104
+ # Examples:
105
+ # irregular 'octopus', 'octopi'
106
+ # irregular 'person', 'people'
107
+ def irregular(singular, plural)
108
+ @uncountables.delete(singular)
109
+ @uncountables.delete(plural)
110
+ if singular[0,1].upcase == plural[0,1].upcase
111
+ plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
112
+ plural(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + plural[1..-1])
113
+ singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
114
+ else
115
+ plural(Regexp.new("#{singular[0,1].upcase}(?i)#{singular[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
116
+ plural(Regexp.new("#{singular[0,1].downcase}(?i)#{singular[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
117
+ plural(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
118
+ plural(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
119
+ singular(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), singular[0,1].upcase + singular[1..-1])
120
+ singular(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), singular[0,1].downcase + singular[1..-1])
121
+ end
122
+ end
123
+
124
+ # Add uncountable words that shouldn't be attempted inflected.
125
+ #
126
+ # Examples:
127
+ # uncountable "money"
128
+ # uncountable "money", "information"
129
+ # uncountable %w( money information rice )
130
+ def uncountable(*words)
131
+ (@uncountables << words).flatten!
132
+ end
133
+
134
+ # Specifies a humanized form of a string by a regular expression rule or by a string mapping.
135
+ # When using a regular expression based replacement, the normal humanize formatting is called after the replacement.
136
+ # When a string is used, the human form should be specified as desired (example: 'The name', not 'the_name')
137
+ #
138
+ # Examples:
139
+ # human /_cnt$/i, '\1_count'
140
+ # human "legacy_col_person_name", "Name"
141
+ def human(rule, replacement)
142
+ @humans.insert(0, [rule, replacement])
143
+ end
144
+
145
+ # Clears the loaded inflections within a given scope (default is <tt>:all</tt>).
146
+ # Give the scope as a symbol of the inflection type, the options are: <tt>:plurals</tt>,
147
+ # <tt>:singulars</tt>, <tt>:uncountables</tt>, <tt>:humans</tt>.
148
+ #
149
+ # Examples:
150
+ # clear :all
151
+ # clear :plurals
152
+ def clear(scope = :all)
153
+ case scope
154
+ when :all
155
+ @plurals, @singulars, @uncountables, @humans = [], [], [], []
156
+ else
157
+ instance_variable_set "@#{scope}", []
158
+ end
159
+ end
160
+ end
161
+
162
+ # Yields a singleton instance of Inflector::Inflections so you can specify additional
163
+ # inflector rules.
164
+ #
165
+ # Example:
166
+ # ActiveSupport::Inflector.inflections do |inflect|
167
+ # inflect.uncountable "rails"
168
+ # end
169
+ def inflections
170
+ if block_given?
171
+ yield Inflections.instance
172
+ else
173
+ Inflections.instance
174
+ end
175
+ end
176
+ end
177
+ end