custom_fielder 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 648a2e684dae174f93a7d853c5b407938e1c8794
4
+ data.tar.gz: 595befc53d7a9bd52f472316d65e6f2c360c6a3c
5
+ SHA512:
6
+ metadata.gz: 4dc3de13896746fcede6569e862bc147e7952fc8238cc277e1cddae8ff763701f8a483750299cec6a8f2098c5bb2c5ae0d308d4a46f0a9fa0135379ff9e44979
7
+ data.tar.gz: cf8ec45b8d4068cabf2ce3620a513015f4acbc3d2cffed34d2033406534ddda6733dae4750ea24dfa234cf4046a42d2b1f4d31ebf1f13ffdc9249f94ada96682
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2016 Nick Hurst
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/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 = 'CustomFielder'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
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
+ Bundler::GemHelper.install_tasks
26
+
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ module CustomFielder
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module CustomFielder
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,83 @@
1
+ module CustomFielder
2
+ module DeserializationHelper
3
+
4
+ FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF']
5
+
6
+ ##
7
+ # @return [Array|Integer|Float|Date|DateTime|Boolean|String]
8
+ #
9
+ def deserialize(type, value)
10
+ send("#{type.underscore}", value)
11
+ end
12
+
13
+ ##
14
+ # @return [Array]
15
+ #
16
+ def array(value)
17
+ value.delete('[]"').split(', ').map do |val|
18
+ case val
19
+ when /^\d+$/
20
+ val.to_i
21
+ when /^\d+\.\d+$/
22
+ val.to_f
23
+ when /^\d{4}-\d{2}-\d{2}$/
24
+ date(val)
25
+ when /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}-\d{2}:\d{2}$/
26
+ date_time(val)
27
+ when 'true'
28
+ true
29
+ when 'false'
30
+ false
31
+ when /".+"/
32
+ val.delete('"')
33
+ else
34
+ val
35
+ end
36
+ end
37
+ end
38
+
39
+ ##
40
+ # @return [Integer]
41
+ #
42
+ def integer(value)
43
+ value.to_i
44
+ end
45
+
46
+ ##
47
+ # @return [Float]
48
+ #
49
+ def float(value)
50
+ value.to_f
51
+ end
52
+
53
+ ##
54
+ # @return [Date]
55
+ #
56
+ def date(value)
57
+ Date.parse(value)
58
+ end
59
+
60
+ ##
61
+ # @return [DateTime]
62
+ #
63
+ def date_time(value)
64
+ DateTime.parse(value)
65
+ end
66
+
67
+ ##
68
+ # @return [Boolean]
69
+ #
70
+ def boolean(value)
71
+ return false if FALSE_VALUES.include?(value)
72
+ true
73
+ end
74
+
75
+ ##
76
+ # @return [String]
77
+ #
78
+ def string(value)
79
+ value
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,88 @@
1
+ module CustomFielder
2
+ module TypeCheckingHelper
3
+
4
+ TRUTH_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON']
5
+ FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF']
6
+
7
+ ##
8
+ # @return [Boolean]
9
+ #
10
+ def is_correct_type?(type, value)
11
+ send("is_#{type.underscore}?", value)
12
+ end
13
+
14
+ ##
15
+ # @return [Boolean]
16
+ #
17
+ def is_array?(value)
18
+ unless value =~ /^\[(.(, )?)+\]$/
19
+ false
20
+ else
21
+ true
22
+ end
23
+ end
24
+
25
+ ##
26
+ # @return [Boolean]
27
+ #
28
+ def is_integer?(value)
29
+ unless value =~ /^\d+$/
30
+ false
31
+ else
32
+ true
33
+ end
34
+ end
35
+
36
+ ##
37
+ # @return [Boolean]
38
+ #
39
+ def is_float?(value)
40
+ unless value =~ /^\d+\.\d+$/
41
+ false
42
+ else
43
+ true
44
+ end
45
+ end
46
+
47
+ ##
48
+ # @return [Boolean]
49
+ #
50
+ def is_date?(value)
51
+ unless value =~ /^\d{4}-\d{2}-\d{2}$/
52
+ false
53
+ else
54
+ true
55
+ end
56
+ end
57
+
58
+ ##
59
+ # @return [Boolean]
60
+ #
61
+ def is_date_time?(value)
62
+ unless value =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}-\d{2}:\d{2}$/
63
+ false
64
+ else
65
+ true
66
+ end
67
+ end
68
+
69
+ ##
70
+ # @return [Boolean]
71
+ #
72
+ def is_boolean?(value)
73
+ unless TRUTH_VALUES.include?(value) or FALSE_VALUES.include?(value)
74
+ false
75
+ else
76
+ true
77
+ end
78
+ end
79
+
80
+ ##
81
+ # @return [Boolean]
82
+ #
83
+ def is_string?(value)
84
+ true
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,180 @@
1
+ module CustomFielder
2
+ class CustomField < ActiveRecord::Base
3
+ include TypeCheckingHelper
4
+ include DeserializationHelper
5
+
6
+ before_validation :set_default
7
+
8
+ validate :check_type
9
+ validate :check_allow_blank
10
+ validate :check_allowed_values
11
+
12
+ belongs_to :field_attributes, dependent: :destroy, class_name: 'FieldAttributes'
13
+ belongs_to :custom_fieldable, polymorphic: true
14
+
15
+ ##
16
+ # Because everything is stored as string with ActiveRecord
17
+ # we use a alias method chain to rename the value method that
18
+ # uses the ActiveRecord String value to raw_value so when
19
+ # value is called it returns the deserialized value
20
+ #
21
+ def value; super; end
22
+ alias_method :raw_value, :value
23
+ def value; deserialize_value; end;
24
+
25
+ ##
26
+ # Adds class methods to deactivate or activate all the fields
27
+ # that belong to the passed attribute object
28
+ #
29
+ class << self
30
+ {
31
+ deactivate_field_for_all: false,
32
+ activate_field_for_all: true
33
+ }.each do |change_field_active_value, field_active_value|
34
+ define_method change_field_active_value do |field_attrs|
35
+ fields = all.where(field_attributes_id: field_attrs.id)
36
+ fields.each do |field|
37
+ field.active = field_active_value
38
+ field.save
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ ##
47
+ # Gets the field type from the field attributes
48
+ #
49
+ # @return [String]
50
+ #
51
+ def type
52
+ @type ||= field_attributes.field_type
53
+ end
54
+
55
+ ##
56
+ # Gets the boolean value of allow blank from field attributes
57
+ #
58
+ # @return [Boolean]
59
+ #
60
+ def allow_blank
61
+ @allow_blank ||= field_attributes.allow_blank
62
+ end
63
+
64
+ ##
65
+ # Gets the array of allowed values from field attributes
66
+ #
67
+ # @return [Array]
68
+ #
69
+ def allowed_values
70
+ @allowed_values ||= begin
71
+ unless field_attributes.allowed_values.nil?
72
+ deserialize('Array', field_attributes.allowed_values)
73
+ else
74
+ nil
75
+ end
76
+ end
77
+ end
78
+
79
+ ##
80
+ # Gets the default value from the field attributes
81
+ #
82
+ # @return [String]
83
+ #
84
+ def default
85
+ @default ||= field_attributes.default
86
+ end
87
+
88
+ ##
89
+ # Deserializes the field value that is stored as a string
90
+ #
91
+ # @return [Array|Integer|Float|Date|DateTime|Boolean|String]
92
+ #
93
+ def deserialize_value
94
+ @deserialized_value ||= deserialize(type, raw_value)
95
+ end
96
+
97
+ ##
98
+ # Sets the value to the default if value is blank
99
+ #
100
+ # @return [Nil]
101
+ #
102
+ def set_default
103
+ if (default and default != '') and (!raw_value or raw_value == '')
104
+ update_attribute(:value, default)
105
+ end
106
+ end
107
+
108
+ ##
109
+ # @return [Boolean|Nil] Adds error if invalid
110
+ #
111
+ def check_type
112
+ if raw_value == nil or raw_value == ''
113
+ return true
114
+ end
115
+
116
+ unless is_correct_type?(type, raw_value)
117
+ value_mismatch_error
118
+ else
119
+ true
120
+ end
121
+ end
122
+
123
+ ##
124
+ # @return [Boolean|Nil] Adds error if invalid
125
+ #
126
+ def check_allow_blank
127
+ if allow_blank == false and (raw_value == nil or raw_value == '')
128
+ value_blank_error
129
+ else
130
+ true
131
+ end
132
+ end
133
+
134
+ ##
135
+ # @return [Boolean|Nil] Adds error if invalid
136
+ #
137
+ def check_allowed_values
138
+ if allowed_values == nil
139
+ return true
140
+ end
141
+
142
+ unless allowed_values.include?(value)
143
+ value_not_allowed_error
144
+ else
145
+ true
146
+ end
147
+ end
148
+
149
+ ##
150
+ # If a value is passed that does not match field type adds
151
+ # a mismatch error
152
+ #
153
+ # @return [nil]
154
+ #
155
+ def value_mismatch_error
156
+ errors.add(:value, 'value passed does not match field type')
157
+ end
158
+
159
+ ##
160
+ # If a value is passed that is blank and allow_blank is false
161
+ # adds a value blank error
162
+ #
163
+ # @return [nil]
164
+ #
165
+ def value_blank_error
166
+ errors.add(:value, 'blank value passed when allow blank is false')
167
+ end
168
+
169
+ ##
170
+ # If a value is passed that is not included in allowed values
171
+ # adds a value not allowed error
172
+ #
173
+ # @return [nil]
174
+ #
175
+ def value_not_allowed_error
176
+ errors.add(:value, 'value passed not in allowed values')
177
+ end
178
+
179
+ end
180
+ end
@@ -0,0 +1,10 @@
1
+ module CustomFielder
2
+ class FieldAttributes < ActiveRecord::Base
3
+ has_many :custom_fields
4
+
5
+ validates :name, presence: true
6
+ validates :field_type, presence: true,
7
+ inclusion: { in: %w[Array Integer Float Date DateTime Boolean String] }
8
+ validates :allow_blank, inclusion: { in: [true, false] }
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>CustomFielder</title>
5
+ <%= stylesheet_link_tag "custom_fielder/application", media: "all" %>
6
+ <%= javascript_include_tag "custom_fielder/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ CustomFielder::Engine.routes.draw do
2
+ end
@@ -0,0 +1,12 @@
1
+ class CreateCustomFielderCustomFields < ActiveRecord::Migration
2
+ def change
3
+ create_table :custom_fielder_custom_fields do |t|
4
+ t.references :custom_fieldable, polymorphic: true, index: { name: 'index_custom_fields_on_fieldable_type_and_fieldable_id' }, null: false
5
+ t.integer :field_attributes_id, null: false
6
+ t.boolean :active, null: false, default: true
7
+ t.string :value
8
+
9
+ t.timestamps null: false
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ class CreateCustomFielderFieldAttributes < ActiveRecord::Migration
2
+ def change
3
+ create_table :custom_fielder_field_attributes do |t|
4
+ t.string :name, null: false
5
+ t.string :field_type, null: false
6
+ t.string :default
7
+ t.boolean :allow_blank, null: false
8
+ t.text :allowed_values, array: true
9
+
10
+ t.timestamps null: false
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ module CustomFielder
2
+ module CustomFieldable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_many :custom_fielder_custom_fields,
7
+ as: :custom_fieldable,
8
+ dependent: :destroy,
9
+ class_name: 'CustomFielder::CustomField'
10
+
11
+ has_many :custom_fielder_field_attributes,
12
+ through: :custom_fielder_custom_fields,
13
+ class_name: 'CustomFielder::FieldAttributes',
14
+ source: :field_attributes
15
+
16
+ alias_method :custom_fields, :custom_fielder_custom_fields
17
+ alias_method :custom_field_attributes, :custom_fielder_field_attributes
18
+
19
+ ##
20
+ # Returns a hash where the keys are the field names
21
+ # and the values are the field values
22
+ #
23
+ # @return [Hash]
24
+ #
25
+ def get_custom_fields_with_values
26
+ custom_fields.inject(Hash.new) do |h, cf|
27
+ field_name = cf.field_attributes.name
28
+ h[field_name] = cf.value
29
+ h
30
+ end
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ module CustomFielder
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace CustomFielder
4
+
5
+ config.generators do |g|
6
+ g.test_framework :rspec
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module CustomFielder
2
+ VERSION = "0.5.0"
3
+ end
@@ -0,0 +1,5 @@
1
+ require "custom_fielder/engine"
2
+
3
+ module CustomFielder
4
+ autoload :CustomFieldable, 'custom_fielder/custom_fieldable'
5
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :custom_fielder do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: custom_fielder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Nick Hurst
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-26 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: 4.2.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.2.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - hurst.178@osu.edu
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - MIT-LICENSE
77
+ - Rakefile
78
+ - app/assets/javascripts/custom_fielder/application.js
79
+ - app/assets/stylesheets/custom_fielder/application.css
80
+ - app/controllers/custom_fielder/application_controller.rb
81
+ - app/helpers/custom_fielder/application_helper.rb
82
+ - app/helpers/custom_fielder/deserialization_helper.rb
83
+ - app/helpers/custom_fielder/type_checking_helper.rb
84
+ - app/models/custom_fielder/custom_field.rb
85
+ - app/models/custom_fielder/field_attributes.rb
86
+ - app/views/layouts/custom_fielder/application.html.erb
87
+ - config/routes.rb
88
+ - db/migrate/20160525133243_create_custom_fielder_custom_fields.rb
89
+ - db/migrate/20160525133922_create_custom_fielder_field_attributes.rb
90
+ - lib/custom_fielder.rb
91
+ - lib/custom_fielder/custom_fieldable.rb
92
+ - lib/custom_fielder/engine.rb
93
+ - lib/custom_fielder/version.rb
94
+ - lib/tasks/custom_fielder_tasks.rake
95
+ homepage: http://www.github.com/no_homepage_yet
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.5.1
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Adds the ability to allow user defined custom fields on models.
119
+ test_files: []
120
+ has_rdoc: