spreeference 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +26 -0
  3. data/README.md +233 -0
  4. data/Rakefile +26 -0
  5. data/app/models/spreeference/app_configuration.rb +9 -0
  6. data/app/models/spreeference/application_record.rb +16 -0
  7. data/app/models/spreeference/preference.rb +6 -0
  8. data/config/routes.rb +2 -0
  9. data/db/migrate/20170217094656_create_spreeference_preferences.rb +10 -0
  10. data/lib/generators/spreeference/install_generator.rb +17 -0
  11. data/lib/generators/templates/app_configuration.rb +6 -0
  12. data/lib/generators/templates/spreeference.rb +12 -0
  13. data/lib/spreeference.rb +16 -0
  14. data/lib/spreeference/configuration.rb +48 -0
  15. data/lib/spreeference/engine.rb +28 -0
  16. data/lib/spreeference/environment.rb +12 -0
  17. data/lib/spreeference/environment_extension.rb +23 -0
  18. data/lib/spreeference/preferable.rb +103 -0
  19. data/lib/spreeference/preferable_methods.rb +52 -0
  20. data/lib/spreeference/scoped_store.rb +34 -0
  21. data/lib/spreeference/store.rb +93 -0
  22. data/lib/spreeference/version.rb +3 -0
  23. data/lib/tasks/spreeference_tasks.rake +4 -0
  24. data/spec/dummy/Rakefile +6 -0
  25. data/spec/dummy/app/assets/config/manifest.js +3 -0
  26. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  27. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  28. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  29. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  30. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  31. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  32. data/spec/dummy/app/jobs/application_job.rb +2 -0
  33. data/spec/dummy/app/models/app_configuration.rb +6 -0
  34. data/spec/dummy/app/models/application_record.rb +3 -0
  35. data/spec/dummy/app/views/layouts/application.html.erb +13 -0
  36. data/spec/dummy/bin/bundle +3 -0
  37. data/spec/dummy/bin/rails +4 -0
  38. data/spec/dummy/bin/rake +4 -0
  39. data/spec/dummy/bin/setup +34 -0
  40. data/spec/dummy/bin/update +29 -0
  41. data/spec/dummy/config.ru +5 -0
  42. data/spec/dummy/config/application.rb +23 -0
  43. data/spec/dummy/config/boot.rb +5 -0
  44. data/spec/dummy/config/cable.yml +9 -0
  45. data/spec/dummy/config/database.yml +25 -0
  46. data/spec/dummy/config/environment.rb +5 -0
  47. data/spec/dummy/config/environments/development.rb +42 -0
  48. data/spec/dummy/config/environments/production.rb +73 -0
  49. data/spec/dummy/config/environments/test.rb +36 -0
  50. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
  51. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  52. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  53. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  54. data/spec/dummy/config/initializers/inflections.rb +16 -0
  55. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  56. data/spec/dummy/config/initializers/new_framework_defaults.rb +24 -0
  57. data/spec/dummy/config/initializers/session_store.rb +3 -0
  58. data/spec/dummy/config/initializers/spreeference.rb +13 -0
  59. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  60. data/spec/dummy/config/locales/en.yml +23 -0
  61. data/spec/dummy/config/puma.rb +47 -0
  62. data/spec/dummy/config/routes.rb +3 -0
  63. data/spec/dummy/config/secrets.yml +22 -0
  64. data/spec/dummy/config/spring.rb +6 -0
  65. data/spec/dummy/db/development.sqlite3 +0 -0
  66. data/spec/dummy/db/schema.rb +23 -0
  67. data/spec/dummy/db/test.sqlite3 +0 -0
  68. data/spec/dummy/log/development.log +69 -0
  69. data/spec/dummy/log/test.log +1995 -0
  70. data/spec/dummy/public/404.html +67 -0
  71. data/spec/dummy/public/422.html +67 -0
  72. data/spec/dummy/public/500.html +66 -0
  73. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  74. data/spec/dummy/public/apple-touch-icon.png +0 -0
  75. data/spec/dummy/public/favicon.ico +0 -0
  76. data/spec/lib/spreeference/configuration_spec.rb +27 -0
  77. data/spec/lib/spreeference/preferable_spec.rb +344 -0
  78. data/spec/lib/spreeference/scoped_store_spec.rb +58 -0
  79. data/spec/lib/spreeference/store_spec.rb +46 -0
  80. data/spec/models/spreeference/preference_spec.rb +80 -0
  81. data/spec/rails_helper.rb +31 -0
  82. data/spec/spec_helper.rb +19 -0
  83. metadata +227 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 681c8829c9221c403c5256195d564a6359958f06
4
+ data.tar.gz: e75097aa1b067440057d13b11f74acf134f763b4
5
+ SHA512:
6
+ metadata.gz: 9fdb7b5bb736fd5af14fc6bdff673fa0cbeb61575d90e96595953ca5ace72887bd36e6643be7b351ffa4f1e67028cefcc281dcabb276da11330651095f97f503
7
+ data.tar.gz: e0b2907110da33fbd032c18591ce35a09534136370a565cb05dc2b08091829633da8d0766e7fabfd9eb95225a65b6dbd0f51db4bf6d9a81a911414cbf9cd5cce
data/LICENSE.md ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2009-2015 Spree Commerce and contributors.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name Spree nor the names of its contributors may be used to
13
+ endorse or promote products derived from this software without specific
14
+ prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,233 @@
1
+ ## Overview
2
+ The reason for this gem is to extract from Spree Core the Preferences functionality, which can be used in other projects besides Spree and e-commerce,
3
+
4
+ Copyright (c) 2009-2015 [Spree Commerce][1] and [Contributors][2], released under the [New BSD License][3]
5
+
6
+ [1]: https://github.com/spree
7
+ [2]: #
8
+ [3]: #
9
+
10
+ Spreeference preferences support general application configuration and preferences per model instance. Additional preferences can be added by your application or included extensions.
11
+
12
+ To implement preferences for a model, simply add a new column called `preferences`. This is an example migration:
13
+
14
+ ```ruby
15
+ class AddPreferencesColumnToProducts < ActiveRecord::Migration[4.2]
16
+ def up
17
+ add_column :products, :preferences, :text
18
+ end
19
+
20
+ def down
21
+ remove_column :products, :preferences
22
+ end
23
+ end
24
+ ```
25
+ This will work if your model is a subclass of `Spreeference::ApplicationRecord`. If found, the `preferences`attribute gets serialized into a `Hash` and merged with the default values.
26
+
27
+ As another example, you might want to add preferences for users to manage their notification settings. Just make sure your `User` model inherits from `Spreeference::ApplicationRecord` then add the `preferences` column. You'll then be able to define preferences for `User`s without adding extra columns to the database table.
28
+
29
+ ### Motivation
30
+
31
+ Preferences for models within an application are very common. Although the rule of thumb is to keep the number of preferences available to a minimum, sometimes it's necessary if you want users to have optional preferences like disabling e-mail notifications.
32
+
33
+ Both use cases are handled by Spreeferences. They are easy to define, provide quick cached reads, persist across restarts and do not require additional columns to be added to your models' tables.
34
+
35
+ ## General Settings
36
+
37
+ Spreeference comes with many application-wide preferences. They are defined in `app/models/spreeference/app_configuration.rb` and made available to your code through `Spreeference::Config`, e.g., `Spreeference::Config.site_name`.
38
+
39
+ You can add additional preferences under the `spreeference/app_configuration` namespace or create your own subclass of `Spreeference::Configuration`.
40
+
41
+ ```ruby
42
+ # These will be saved with key: spreeference/app_configuration/hot_salsa
43
+ Spreeference::AppConfiguration.class_eval do
44
+ preference :hot_salsa, :boolean
45
+ preference :dark_chocolate, :boolean, default: true
46
+ preference :color, :string
47
+ preference :favorite_number
48
+ preference :language, :string, default: 'English'
49
+ end
50
+
51
+ # Spreeference::Config is an instance of Spreeference::AppConfiguration
52
+ Spreeference::Config.hot_salsa = false
53
+
54
+ # Create your own class
55
+ # These will be saved with key: kona/store_configuration/hot_coffee
56
+ Kona::StoreConfiguration < Spreeference::Configuration
57
+ preference :hot_coffee, :boolean
58
+ preference :color, :string, default: 'black'
59
+ end
60
+
61
+ KONA::STORE_CONFIG = Kona::StoreConfiguration.new
62
+ puts KONA::STORE_CONFIG.hot_coffee
63
+ ```
64
+
65
+ ## Defining Preferences
66
+
67
+ You can define preferences for a model within the model itself:
68
+
69
+ ```ruby
70
+ class User < Spreeference::ApplicationRecord
71
+ preference :hot_salsa, :boolean
72
+ preference :dark_chocolate, :boolean, default: true
73
+ preference :color, :string
74
+ preference :favorite_number, :integer
75
+ preference :language, :string, default: "English"
76
+ end
77
+ ```
78
+ In the above model, five preferences have been defined:
79
+
80
+ * `hot_salsa`
81
+ * `dark_chocolate`
82
+ * `color`
83
+ * `favorite_number`
84
+ * `language`
85
+
86
+ For each preference, a data type is provided. The types available are:
87
+
88
+ * `boolean`
89
+ * `string`
90
+ * `password`
91
+ * `integer`
92
+ * `text`
93
+ * `array`
94
+ * `hash`
95
+
96
+ An optional default value may be defined which will be used unless a value has been set for that specific instance.
97
+
98
+ ## Accessing Preferences
99
+
100
+ Once preferences have been defined for a model, they can be accessed either using the shortcut methods that are generated for each preference or the generic methods that are not specific to a particular preference.
101
+
102
+ ### Shortcut Methods
103
+
104
+ There are several shortcut methods that are generated. They are shown below.
105
+
106
+ Query methods:
107
+
108
+ ```ruby
109
+ user.prefers_hot_salsa? # => false
110
+ user.prefers_dark_chocolate? # => false
111
+ ```
112
+
113
+ Reader methods:
114
+
115
+ ```ruby
116
+ user.preferred_color # => nil
117
+ user.preferred_language # => "English"
118
+ ```
119
+
120
+ Writer methods:
121
+
122
+ ```ruby
123
+ user.prefers_hot_salsa = false # => false
124
+ user.preferred_language = "English" # => "English"
125
+ ```
126
+
127
+ Check if a preference is available:
128
+
129
+ ```ruby
130
+ user.has_preference? :hot_salsa
131
+ ```
132
+
133
+ ### Generic Methods
134
+
135
+ Each shortcut method is essentially a wrapper for the various generic methods shown below:
136
+
137
+ Query method:
138
+
139
+ ```ruby
140
+ user.prefers?(:hot_salsa) # => false
141
+ user.prefers?(:dark_chocolate) # => false
142
+ ```
143
+
144
+ Reader methods:
145
+
146
+ ```ruby
147
+ user.preferred(:color) # => nil
148
+ user.preferred(:language) # => "English"
149
+ ```
150
+
151
+ ```ruby
152
+ user.get_preference :color
153
+ user.get_preference :language
154
+ ```
155
+
156
+ Writer method:
157
+
158
+ ```ruby
159
+ user.set_preference(:hot_salsa, false) # => false
160
+ user.set_preference(:language, "English") # => "English"
161
+ ```
162
+ ### Accessing All Preferences
163
+
164
+ You can get a hash of all stored preferences by accessing the `preferences` helper:
165
+
166
+ ```ruby
167
+ user.preferences # => {"language"=>"English", "color"=>nil}
168
+ ```
169
+
170
+ This hash will contain the value for every preference that has been defined for the model instance, whether the value is the default or one that has been previously stored.
171
+
172
+ ### Default and Type
173
+
174
+ You can access the default value for a preference:
175
+
176
+ ```ruby
177
+ user.preferred_color_default # => 'blue'
178
+ ```
179
+
180
+ Types are used to generate forms or display the preference. You can also get the type defined for a preference:
181
+
182
+ ```ruby
183
+ user.preferred_color_type # => :string
184
+ ```
185
+ ### Configuration Through an Initializer
186
+
187
+ During the Spreeference installation process, an initializer file is created within your application's source code. The initializer is found under `config/initializers/spreeference.rb`:
188
+
189
+ ```ruby
190
+ Spreeference.config do |config|
191
+ # Example:
192
+ # Uncomment to override the default site name.
193
+ # config.site_name = "Spree Demo Site"
194
+ end
195
+ ```
196
+ The `Spreeference.config` block acts as a shortcut to setting `Spreeference::Config` multiple times. If you have multiple default preferences you would like to override within your code you may override them here. Using the initializer for setting the defaults is a nice shortcut, and helps keep your preferences organized in a standard location.
197
+
198
+ ## Site-Wide Preferences
199
+
200
+ You can define preferences that are site-wide and don't apply to a specific instance of a model by creating a configuration file that inherits from `Spreeference::Configuration`.
201
+
202
+ ```ruby
203
+ class MyApplicationConfiguration < Spreeference::Configuration
204
+ preference :theme, :string, default: "Default"
205
+ preference :show_splash_page, :boolean
206
+ preference :number_of_articles, :integer
207
+ end
208
+ ```
209
+
210
+ In the above configuration file, three preferences have been defined:
211
+
212
+ * theme
213
+ * show_splash_page
214
+ * number_of_articles
215
+
216
+ ### Configuring Site-Wide Preferences
217
+
218
+ The recommended way to configure site-wide preferences is through an initializer. Let's take a look at configuring the preferences defined in the previous configuration example.
219
+
220
+ ```ruby
221
+ module Spree
222
+ MyApp::Config = MyApplicationConfiguration.new
223
+ end
224
+
225
+ MyApp::Config[:theme] = "blue_theme"
226
+ MyApp::Config[:show_spash_page] = true
227
+ MyApp::Config[:number_of_articles] = 5
228
+ ```
229
+
230
+ The `MyApp` name used here is an example and should be replaced with your actual application's name, found in `config/application.rb`.
231
+
232
+ The above example will configure the preferences we defined earlier. Take note of the second line. In order to set and get preferences using `MyApp::Config`, we must first instantiate the configuration object.
233
+
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Spreeference'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ require 'bundler/gem_tasks'
26
+
@@ -0,0 +1,9 @@
1
+ module Spreeference
2
+ class AppConfiguration < Spreeference::Configuration
3
+ # preference :checkbox, :boolean, default: true
4
+ # preference :input, :string, default:'changeme'
5
+ # preference :number, :integer, default: 123
6
+ # preference :list, :array, default:[]
7
+ preference :is_ok, :string, default:'Nice!'
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ module Spreeference
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ include Spreeference::Preferable
4
+
5
+ serialize :preferences, Hash
6
+
7
+ after_initialize do
8
+ if has_attribute?(:preferences) && !preferences.nil?
9
+ self.preferences = default_preferences.merge(preferences)
10
+ end
11
+ end
12
+
13
+ self.abstract_class = true
14
+
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ module Spreeference
2
+ class Preference < Spreeference::ApplicationRecord
3
+ serialize :value
4
+ validates :key, presence: true, uniqueness: { allow_blank: true }
5
+ end
6
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ Rails.application.routes.draw do
2
+ end
@@ -0,0 +1,10 @@
1
+ class CreateSpreeferencePreferences < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :spreeference_preferences do |t|
4
+ t.string :key
5
+ t.text :value
6
+ t.timestamps
7
+ end
8
+ add_index :spreeference_preferences, :key, unique: true
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ require 'rails/generators'
2
+ module Spreeference::Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../../templates", __FILE__)
5
+
6
+ desc 'Add app_configuration.rb'
7
+ def copy_app_configuration_file
8
+ copy_file "app_configuration.rb", "app/models/app_configuration.rb"
9
+ end
10
+
11
+ desc 'Add Spreeference configuration in initializers'
12
+ def copy_configuration_file
13
+ copy_file "spreeference.rb", "config/initializers/spreeference.rb"
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ class AppConfiguration < Spreeference::Configuration
2
+ # preference :checkbox, :boolean, default: true
3
+ # preference :input, :string, default:'changeme'
4
+ # preference :number, :integer, default: 123
5
+ # preference :list, :array, default:[]
6
+ end
@@ -0,0 +1,12 @@
1
+ # Configure Spree Preferences
2
+ #
3
+ # Note: If a preference is set here it will be stored within the cache & database upon initialization.
4
+ # Just removing an entry from this initializer will not make the preference value go away.
5
+ # Instead you must either set a new value or remove entry, clear cache, and remove database entry.
6
+ #
7
+ # In order to initialize a setting do:
8
+ # config.setting_name = 'new value'
9
+ Spreeference.config do |config|
10
+ # Example:
11
+ # config.is_ok = 'Nice!'
12
+ end
@@ -0,0 +1,16 @@
1
+ require 'spreeference/preferable_methods'
2
+ require 'spreeference/preferable'
3
+ require 'spreeference/configuration'
4
+ require 'spreeference/scoped_store'
5
+ require 'spreeference/store'
6
+ require 'spreeference/environment_extension'
7
+ require 'spreeference/environment'
8
+
9
+ module Spreeference
10
+
11
+ def self.config
12
+ yield(Spreeference::Config)
13
+ end
14
+ end
15
+
16
+ require "spreeference/engine"
@@ -0,0 +1,48 @@
1
+ module Spreeference
2
+ class Configuration
3
+ include Spreeference::Preferable
4
+
5
+ def configure
6
+ yield(self) if block_given?
7
+ end
8
+
9
+ def preferences
10
+ Spreeference::ScopedStore.new(self.class.name.underscore)
11
+ end
12
+
13
+ def reset
14
+ preferences.each do |name, value|
15
+ set_preference name, preference_default(name)
16
+ end
17
+ end
18
+
19
+ alias :[] :get_preference
20
+ alias :[]= :set_preference
21
+ alias :get :get_preference
22
+
23
+ def set(*args)
24
+ options = args.extract_options!
25
+ options.each do |name, value|
26
+ set_preference name, value
27
+ end
28
+
29
+ if args.size == 2
30
+ set_preference args[0], args[1]
31
+ end
32
+ end
33
+
34
+ def method_missing(method, *args)
35
+ name = method.to_s.gsub('=', '')
36
+ if has_preference? name
37
+ if method.to_s =~ /=$/
38
+ set_preference(name, args.first)
39
+ else
40
+ get_preference name
41
+ end
42
+ else
43
+ super
44
+ end
45
+ end
46
+
47
+ end
48
+ end