web-connect 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +1 -0
  3. data/Rakefile +3 -0
  4. data/lib/netfira/web_connect/components/checksum.rb +19 -0
  5. data/lib/netfira/web_connect/components/guid.rb +11 -0
  6. data/lib/netfira/web_connect/components/octa_word.rb +73 -0
  7. data/lib/netfira/web_connect/components.rb +1 -0
  8. data/lib/netfira/web_connect/configuration.rb +33 -0
  9. data/lib/netfira/web_connect/db_schema/20140514_support.rb +38 -0
  10. data/lib/netfira/web_connect/db_schema/20140515_alpha.rb +106 -0
  11. data/lib/netfira/web_connect/events.rb +14 -0
  12. data/lib/netfira/web_connect/migration/base_methods.rb +59 -0
  13. data/lib/netfira/web_connect/migration/refinements.rb +16 -0
  14. data/lib/netfira/web_connect/migration.rb +101 -0
  15. data/lib/netfira/web_connect/model/record/digests.rb +24 -0
  16. data/lib/netfira/web_connect/model/record/events.rb +35 -0
  17. data/lib/netfira/web_connect/model/record/file_record.rb +79 -0
  18. data/lib/netfira/web_connect/model/record/materialization.rb +59 -0
  19. data/lib/netfira/web_connect/model/record/relations.rb +51 -0
  20. data/lib/netfira/web_connect/model/record/sendable.rb +29 -0
  21. data/lib/netfira/web_connect/model/record/serializer.rb +56 -0
  22. data/lib/netfira/web_connect/model/record/translated_string.rb +42 -0
  23. data/lib/netfira/web_connect/model/record/translation.rb +58 -0
  24. data/lib/netfira/web_connect/model/record/translations.rb +63 -0
  25. data/lib/netfira/web_connect/model/record/tree.rb +13 -0
  26. data/lib/netfira/web_connect/model/record.rb +132 -0
  27. data/lib/netfira/web_connect/model/relation/events.rb +34 -0
  28. data/lib/netfira/web_connect/model/relation.rb +67 -0
  29. data/lib/netfira/web_connect/model/support.rb +13 -0
  30. data/lib/netfira/web_connect/model.rb +33 -0
  31. data/lib/netfira/web_connect/models/image.rb +48 -0
  32. data/lib/netfira/web_connect/models/order.rb +5 -0
  33. data/lib/netfira/web_connect/models/order_line.rb +13 -0
  34. data/lib/netfira/web_connect/models/support/setting.rb +31 -0
  35. data/lib/netfira/web_connect/models/support/shop/settings.rb +42 -0
  36. data/lib/netfira/web_connect/models/support/shop.rb +22 -0
  37. data/lib/netfira/web_connect/models/support/table.rb +5 -0
  38. data/lib/netfira/web_connect/models.rb +73 -0
  39. data/lib/netfira/web_connect/rack_app/action.rb +66 -0
  40. data/lib/netfira/web_connect/rack_app/action_helpers/data_types.rb +22 -0
  41. data/lib/netfira/web_connect/rack_app/action_helpers/env_importer.rb +59 -0
  42. data/lib/netfira/web_connect/rack_app/action_helpers/env_methods.rb +23 -0
  43. data/lib/netfira/web_connect/rack_app/actions/version_1/not_supported.rb +11 -0
  44. data/lib/netfira/web_connect/rack_app/actions/version_8/checksums.rb +14 -0
  45. data/lib/netfira/web_connect/rack_app/actions/version_8/commit/records.rb +45 -0
  46. data/lib/netfira/web_connect/rack_app/actions/version_8/commit/relations.rb +48 -0
  47. data/lib/netfira/web_connect/rack_app/actions/version_8/commit.rb +33 -0
  48. data/lib/netfira/web_connect/rack_app/actions/version_8/files.rb +21 -0
  49. data/lib/netfira/web_connect/rack_app/actions/version_8/info.rb +18 -0
  50. data/lib/netfira/web_connect/rack_app/actions/version_8/settings.rb +79 -0
  51. data/lib/netfira/web_connect/rack_app/exceptions/http_exception.rb +44 -0
  52. data/lib/netfira/web_connect/rack_app/exceptions.rb +6 -0
  53. data/lib/netfira/web_connect/rack_app.rb +56 -0
  54. data/lib/netfira/web_connect/request_filter.rb +66 -0
  55. data/lib/netfira/web_connect/schema/table.rb +58 -0
  56. data/lib/netfira/web_connect/schema.rb +22 -0
  57. data/lib/netfira/web_connect/version.rb +5 -0
  58. data/lib/netfira/web_connect.rb +82 -0
  59. data/lib/netfira.rb +10 -0
  60. data/lib/web_connect.rb +1 -0
  61. metadata +246 -0
@@ -0,0 +1,51 @@
1
+ module Netfira::WebConnect
2
+ class Model::Record
3
+
4
+ # These methods help relate and unrelate records
5
+ module Relations
6
+
7
+ def relate(record)
8
+ error_messages = {
9
+ no_relation: 'You cannot add a %s to a %s',
10
+ wrong_shop: 'Tried to add a record from shop %s to shop %s'
11
+ }
12
+ prepare_relation(record, error_messages) do |relation_class, attrs|
13
+ relation_class.find_or_create_by attrs
14
+ end
15
+ end
16
+
17
+ alias_method :<<, :relate
18
+
19
+ def unrelate(record)
20
+ error_messages = {
21
+ no_relation: 'You cannot remove a %s from a %s',
22
+ wrong_shop: 'Tried to remove a record of shop %s from shop %s'
23
+ }
24
+ prepare_relation(record, error_messages) do |relation_class, attrs|
25
+ relation_class.where(attrs).destroy_all
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ # This method assists #relate and #unrelate
32
+ def prepare_relation(record, error_messages)
33
+
34
+ # The class of the relation between self and record
35
+ relation_class = Model::Record::Relation.for(self, record)
36
+
37
+ # Error for unrelatable classes
38
+ raise error_messages[:no_relation] % [record.class.name.demodulize, self.class.name.demodulize] unless relation_class
39
+
40
+ # Error for shop mismatches
41
+ raise error_messages[:wrong_shop] % [record.shop_id, shop_id] unless shop_id == record.shop_id
42
+
43
+ # The attributes to use for create or delete, e.g. {product_id: 1, category_id: 2}
44
+ attrs = [self, record].map{ |r| ["#{r.class.name.demodulize.underscore}_id", r.id]}.to_h
45
+
46
+ yield relation_class, attrs
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,29 @@
1
+ module Netfira::WebConnect
2
+ class Model::Record
3
+
4
+ module Sendable
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ after_initialize :create_guid
9
+ enum delivery_status: [:unsent, :sent, :delivered]
10
+ end
11
+
12
+ def guid
13
+ @guid ||= Guid.from(self[:guid])
14
+ end
15
+
16
+ def guid=(value)
17
+ raise 'GUIDs are read-only'
18
+ end
19
+
20
+ private
21
+
22
+ def create_guid
23
+ self[:guid] ||= (@guid = Guid.create).b
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,56 @@
1
+ require 'bigdecimal'
2
+
3
+ module Netfira::WebConnect
4
+ class Model::Record
5
+
6
+ module Serializer
7
+ extend ActiveSupport::Concern
8
+
9
+ EXCLUDE_FROM_SERIALIZE = %w[id shop_id digest delivery_status created_at updated_at]
10
+
11
+ included do
12
+
13
+ private
14
+
15
+ # Returns an array of three arrays of keys, e.g.
16
+ # [ ['product_id', 'unit_price'], ['description'], [] ]
17
+ def self.attributes_to_serialize
18
+ @attributes_to_serialize ||= [
19
+ attribute_names - EXCLUDE_FROM_SERIALIZE,
20
+ has_languages? ? self::Translation.translated_attribute_names : [],
21
+ [] # Custom attributes (not implemented)
22
+ ]
23
+ end
24
+ end
25
+
26
+ def to_s
27
+
28
+ # Map each array of keys from the above method into a sorted hash of key/value pairs
29
+ data = self.class.attributes_to_serialize.map do |keys|
30
+ pairs = keys.sort.map do |key|
31
+ [key.camelize(:lower), cast_for_serialization(__send__ key)]
32
+ end
33
+ pairs.reject!{ |v| v[1].nil? }.to_h
34
+ end
35
+
36
+ # Return the class name and the sets above, e.g. Product{...},{...},{...}
37
+ self.class.name.demodulize << JSON.generate(data)[1..-2]
38
+ end
39
+
40
+ private
41
+
42
+ def cast_for_serialization(value)
43
+ if TranslatedString === value
44
+ value = value.sort
45
+ value = value.empty? ? nil : value.to_h
46
+ elsif Numeric === value
47
+ value = (value == value.floor) ? value.to_i : value.to_f
48
+ elsif OctaWord === value
49
+ value = value.to_s
50
+ end
51
+ value
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,42 @@
1
+ require 'forwardable'
2
+
3
+ module Netfira::WebConnect
4
+
5
+ # This class represents a translated string on a model, e.g. product.description.
6
+ # Callbacks are supplied by the Model::Record::Translations mixin
7
+ class Model::Record::TranslatedString
8
+ extend Forwardable
9
+
10
+ def initialize
11
+ @callbacks = {}
12
+ end
13
+
14
+ def [](lang)
15
+ @callbacks[:get].call lang
16
+ end
17
+
18
+ def []=(lang, value)
19
+ @callbacks[:set].call lang, value
20
+ end
21
+
22
+ def on(action, &block)
23
+ @callbacks[action] = block
24
+ end
25
+
26
+ def to_s
27
+ self[nil]
28
+ end
29
+
30
+ def to_h
31
+ @callbacks[:all].call
32
+ end
33
+
34
+ def merge!(values)
35
+ values.each{ |key, value| self[key] = value }
36
+ self
37
+ end
38
+
39
+ delegate %i[count length size each map sort select reject] => :to_h
40
+
41
+ end
42
+ end
@@ -0,0 +1,58 @@
1
+ module Netfira::WebConnect
2
+
3
+ # Subclasses of this model represents rows from translation tables, e.g. nf_products_l10n.
4
+ # Subclasses are materialized when their parent record models are materialized.
5
+ class Model::Record::Translation
6
+
7
+ class << self
8
+
9
+ def materialize(owner_class)
10
+
11
+ # Make a translation model, e.g. Product::Translation
12
+ klass = Class.new(self)
13
+ owner_class.const_set :Translation, klass
14
+
15
+ # Keep a reference to the owner class
16
+ klass.instance_variable_set :@owner_class, owner_class
17
+
18
+ # Give translations references back to their parent records
19
+ klass.belongs_to :owner,
20
+ class_name: owner_class.name,
21
+ foreign_key: "#{owner_class.name.demodulize.underscore}_id",
22
+ inverse_of: :translation_models
23
+
24
+ # Add a translations relation, e.g. product.translations
25
+ owner_class.has_many :translation_models,
26
+ class_name: klass.name,
27
+ inverse_of: :owner,
28
+ autosave: true
29
+
30
+ # Add translations to the default scope, as they will almost
31
+ # always be needed for lookups
32
+ owner_class.default_scope { includes :translation_models }
33
+
34
+ end
35
+
36
+ def translated_attribute_names
37
+ @translated_attribute_names ||= attribute_names - ['id', 'language', "#{@owner_class.single_name}_id"]
38
+ end
39
+
40
+ def table_name
41
+ @table_name ||= if self == Model::Record::Translation
42
+ Models::Table.table_name
43
+ else
44
+ Netfira::WebConnect.db_table_prefix(plural_name).to_s
45
+ end
46
+ end
47
+
48
+ def single_name
49
+ @single_name ||= Netfira::WebConnect.db_table_l10n_suffix @owner_class.single_name
50
+ end
51
+
52
+ def plural_name
53
+ @plural_name ||= Netfira::WebConnect.db_table_l10n_suffix @owner_class.plural_name
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,63 @@
1
+ module Netfira::WebConnect
2
+ class Model::Record
3
+
4
+ # This module is mixed into records that have translations.
5
+ module Translations
6
+
7
+ # Called when getting a translated string, e.g. product.description
8
+ def get_translated_string(key)
9
+ translated_string_for key
10
+ end
11
+
12
+ # Called when assigning a translated string, e.g. product.description = 'Stuff'
13
+ def set_translated_string(key, value)
14
+ if Hash === value
15
+ replace_translations_for key, value
16
+ else
17
+ translated_string_for(key)[nil] = value
18
+ end
19
+ end
20
+
21
+ def locale
22
+ shop.locale
23
+ end
24
+
25
+ private
26
+
27
+ def translations
28
+ @translations ||= translation_models.map{ |model| [model.language, model]}.to_h
29
+ end
30
+
31
+ def translated_strings
32
+ @translated_strings ||= {}
33
+ end
34
+
35
+ def translation_for_language(lang)
36
+ lang = lang.to_s
37
+ translations[lang] ||= translation_models.build(language: lang)
38
+ end
39
+
40
+ def replace_translations_for(key, value)
41
+ translations.each { |lang, model| model[key] = value[lang] }
42
+ translated_string_for(key).merge! value
43
+ end
44
+
45
+ def translated_string_for(key)
46
+ translated_strings[key] ||= begin
47
+ t = Model::Record::TranslatedString.new
48
+ t.on(:get) { |lang| translation_for_language(lang || locale).__send__ key }
49
+ t.on(:set) { |lang, value| translation_for_language(lang || locale).__send__ :"#{key}=", value }
50
+ t.on(:all) { translations.map{ |lang, model| [lang, model[key]] }.reject{ |x| x[1].nil? }.to_h }
51
+ t
52
+ end
53
+ end
54
+
55
+ def clear_translations
56
+ @translations = nil
57
+ @translated_strings = nil
58
+ self
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,13 @@
1
+ module Netfira::WebConnect
2
+ module Model::Record::Tree
3
+
4
+ def children
5
+ self.class.where(parent_id: id)
6
+ end
7
+
8
+ def parent
9
+ @parent ||= parent_id && self.class.find_by(id: parent_id)
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,132 @@
1
+ require_relative 'record/relations'
2
+ require_relative 'record/materialization'
3
+ require_relative 'record/serializer'
4
+ require_relative 'record/digests'
5
+ require_relative 'record/sendable'
6
+ require_relative 'record/events'
7
+
8
+ module Netfira::WebConnect
9
+ class Model::Record
10
+ extend Materialization
11
+ include Relations
12
+ include Serializer
13
+ include Digests
14
+ include Events
15
+
16
+ class << self
17
+
18
+ def table_name
19
+ @table_name ||= if self == Model::Record
20
+ Models::Table.table_name
21
+ else
22
+ Netfira::WebConnect.db_table_prefix(plural_name).to_s
23
+ end
24
+ end
25
+
26
+ def has_languages?
27
+ const_defined? :Translation, false
28
+ end
29
+
30
+ def tree?
31
+ @is_tree ||= attribute_names.include? 'parent_id'
32
+ end
33
+
34
+ def origin_key
35
+ @origin_key ||= if sendable?
36
+ :guid
37
+ elsif writable?
38
+ nil
39
+ else
40
+ (table_props.origin_key || "#{single_name}_id").to_sym
41
+ end
42
+ end
43
+
44
+ def writable?
45
+ @writable ||= table_props.writable
46
+ end
47
+
48
+ def sendable?
49
+ @sendable ||= table_props.sendable
50
+ end
51
+
52
+ def find_by_origin_id(shop, id)
53
+ id = id.b if OctaWord === id
54
+ find_by origin_key => id, shop_id: shop.id
55
+ end
56
+
57
+ def find_or_initialize_by_origin_id(shop, id)
58
+ find_by_origin_id(shop, id) || new(origin_key => id, shop_id: shop.id)
59
+ end
60
+
61
+ def find_or_create_by_origin_id(shop, id)
62
+ record = find_or_initialize_by_origin_id(shop, id)
63
+ record.save unless record.persisted?
64
+ record
65
+ end
66
+
67
+ def has_file?
68
+ @has_file ||= self < FileRecord
69
+ end
70
+
71
+ def schema
72
+ @schema ||= Netfira::WebConnect.schema[self]
73
+ end
74
+
75
+ end
76
+
77
+ after_initialize :init
78
+
79
+ %i[has_languages? tree? origin_key writable? sendable? has_file?].each do |method|
80
+ define_method(method) { self.class.__send__ method }
81
+ end
82
+
83
+ def origin_id
84
+ __send__ origin_key
85
+ end
86
+
87
+ def as_readonly
88
+ readonly!
89
+ yield
90
+ instance_variable_set :@readonly, false
91
+ end
92
+
93
+ def reload
94
+ clear_translations if has_languages?
95
+ super
96
+ end
97
+
98
+ def write_with_type_casting(key, value)
99
+ schema = self.class.schema
100
+ if schema.localize.include? key
101
+ set_translated_string key, value
102
+ else
103
+ type = schema.columns[key]
104
+ return false unless type
105
+ value = value.to_s if type == 'string'
106
+ write_attribute key, value
107
+ end
108
+ true
109
+ end
110
+
111
+ private
112
+
113
+ def self.table_props
114
+ @table_props
115
+ end
116
+
117
+ def init
118
+ self.shop_id ||= 0
119
+ end
120
+
121
+ def after_add_relation(model)
122
+ model.shop_id = shop_id
123
+ end
124
+
125
+ end
126
+ end
127
+
128
+ require_relative 'record/file_record'
129
+ require_relative 'record/translated_string'
130
+ require_relative 'record/translation'
131
+ require_relative 'record/translations'
132
+ require_relative 'record/tree'
@@ -0,0 +1,34 @@
1
+ module Netfira::WebConnect
2
+ class Model::Relation
3
+ module Events
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ after_save :dispatch_create
8
+ after_destroy :dispatch_destroy
9
+ end
10
+
11
+ private
12
+
13
+ def dispatch_create
14
+ dispatch_relation_event 'add_%s_to_%s'
15
+ end
16
+
17
+ def dispatch_destroy
18
+ dispatch_relation_event 'remove_%s_from_%s'
19
+ end
20
+
21
+ def dispatch_relation_event(event_name_template)
22
+ [records, records.reverse].each do |records|
23
+ event_name = (event_name_template % records.map{ |record| record.class.single_name }).to_sym
24
+ records[0].as_readonly do
25
+ records[1].as_readonly do
26
+ Netfira::WebConnect.dispatch_event event_name, *records
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,67 @@
1
+ require_relative 'relation/events'
2
+
3
+ module Netfira::WebConnect
4
+ class Model::Relation
5
+ include Events
6
+
7
+ class << self
8
+
9
+ attr_reader :related_classes
10
+
11
+ def materialize(name_a, name_b)
12
+ klass = Class.new(self)
13
+ Models.const_set "#{name_a}To#{name_b}", klass
14
+ klass.related_classes = [name_a, name_b].map{ |n| Models.const_get n.camelize.singularize }
15
+ end
16
+
17
+ def related_classes=(classes)
18
+ raise 'Related classes have already been set' if related_classes
19
+ @related_classes = classes
20
+ classes.each_with_index do |related_class, index|
21
+
22
+ # The class on the opposite side of the relation. For example:
23
+ # related_class => Product
24
+ # opposite_class => Category
25
+ opposite_class = related_classes[1 - index]
26
+
27
+ # Name of the reference to add to the related class, e.g. Product#category_relations
28
+ relation_name = :"#{opposite_class.single_name}_relations"
29
+
30
+ # The relation class's reference, e.g. CategoryToProduct#product
31
+ belongs_to related_class.single_name.to_sym
32
+
33
+ # The related class's reference to the relation, e.g. Product#category_relations
34
+ related_class.has_many relation_name,
35
+ class_name: name,
36
+ inverse_of: related_class.single_name.to_sym
37
+
38
+ # The related class's reference to the other related class,
39
+ # e.g. Product#categories (at last!)
40
+ related_class.has_many opposite_class.plural_name.to_sym,
41
+ through: relation_name,
42
+ after_add: :after_add_relation
43
+
44
+ end
45
+ end
46
+
47
+ def table_name
48
+ @table_name ||= if self == Model::Relation
49
+ Models::Table.table_name
50
+ else
51
+ Netfira::WebConnect.db_table_prefix(related_classes.map(&:plural_name).join '_to_').to_s
52
+ end
53
+ end
54
+
55
+ def for(class_a, class_b)
56
+ name = [class_a, class_b].map{ |c| (c.is_a?(Class) ? c : c.class).name.demodulize }.sort.join 'To'
57
+ Models.const_get name if Models.const_defined? name
58
+ end
59
+
60
+ end
61
+
62
+ def records
63
+ self.class.related_classes.map{ |klass| __send__ klass.single_name.to_sym }
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,13 @@
1
+ module Netfira::WebConnect
2
+ class Model::Support
3
+
4
+ def self.table_name
5
+ @table_name ||= if self == Model::Support
6
+ Models::Table.table_name
7
+ else
8
+ Netfira::WebConnect.db_table_prefix('_' << name.demodulize.underscore.pluralize).to_s
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ module Netfira::WebConnect
2
+ class Model < ActiveRecord::Base
3
+ class Record < self
4
+ class FileRecord < self
5
+ end
6
+ class Translation < Model
7
+ end
8
+ end
9
+ class Relation < self
10
+ end
11
+ class Support < self
12
+ end
13
+
14
+ class << self
15
+ def table_name
16
+ Models::Table.table_name
17
+ end
18
+
19
+ def single_name
20
+ @single_name ||= name.demodulize.underscore
21
+ end
22
+
23
+ def plural_name
24
+ @plural_name ||= single_name.pluralize
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+
31
+ require_relative 'model/record'
32
+ require_relative 'model/relation'
33
+ require_relative 'model/support'
@@ -0,0 +1,48 @@
1
+ require 'ostruct'
2
+ require 'fastimage'
3
+
4
+ module Netfira::WebConnect
5
+ class Models::Image < Model::Record::FileRecord
6
+
7
+ def focus_point=(point)
8
+ self.focus_point_top = point[:top]
9
+ self.focus_point_left = point[:left]
10
+ self.focus_point
11
+ end
12
+
13
+ def focus_point
14
+ @focus_point ||= FocusPoint.new(self)
15
+ end
16
+
17
+ def data=(value)
18
+ super value
19
+ self.width, self.height = FastImage.size(attachment.staged_path)
20
+ end
21
+
22
+ def dimensions
23
+ [width, height]
24
+ end
25
+
26
+ def dimensions=(value)
27
+ self.width, self.height = value
28
+ end
29
+
30
+ class FocusPoint
31
+
32
+ def initialize(image)
33
+ @image = image
34
+ end
35
+
36
+ %w[top left].each do |attr|
37
+ define_method :"#{attr}" do
38
+ @image[:"focus_point_#{attr}"]
39
+ end
40
+ define_method :"#{attr}=" do |value|
41
+ @image[:"focus_point_#{attr}"] = value
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ module Netfira::WebConnect
2
+ class Models::Order < Model::Record
3
+ has_many :lines, class_name: "#{name}Line"
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ module Netfira::WebConnect
2
+ class Models::OrderLine < Model::Record
3
+ belongs_to :order
4
+
5
+ after_initialize :set_defaults
6
+
7
+ private
8
+
9
+ def set_defaults
10
+ self.quantity ||= 1
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,31 @@
1
+ module Netfira::WebConnect
2
+ class Models::Setting < Model::Support
3
+
4
+ belongs_to :shop, inverse_of: :setting_models
5
+
6
+ def typed_value
7
+ case content_type
8
+ when 'application/json' then JSON.parse(value, quirks_mode: true)
9
+ when 'application/octet-stream' then value.b
10
+ when /^text\/plain;charset=(.+)$/ then value.force_encoding($1)
11
+ else value
12
+ end
13
+ end
14
+
15
+ def typed_value=(value)
16
+ if String === value
17
+ if value.encoding.name == 'ASCII-8BIT'
18
+ self.value = value.b
19
+ self.content_type = 'application/octet-stream'
20
+ else
21
+ self.value = value.force_encoding('UTF-8')
22
+ self.content_type = 'text/plain;charset=UTF-8'
23
+ end
24
+ else
25
+ self.value = JSON.generate(value, quirks_mode: true)
26
+ self.content_type = 'application/json'
27
+ end
28
+ end
29
+
30
+ end
31
+ end