coaster 0.4.7 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 87a3bfb2be6aec0a47f770b352bcd01988627bb3
4
- data.tar.gz: b610ad99c8a1933e7baf37d88e9267daa1cccb7c
3
+ metadata.gz: 3f3443395e8b26f474e4d170c1dd1e3edea41cf9
4
+ data.tar.gz: 482a7957080674361a16c29a6284e7f819c8248e
5
5
  SHA512:
6
- metadata.gz: abf2b202fb7f15967a44a4f8ccfcae931fd910aebb3ccf28253d7497877b538fe2297f4e64edc6915e87a3d341797a104b52d1159966c619fcc969814ed0c28a
7
- data.tar.gz: bafd012b8095e7a7fe93884503ffc52902b7e2b8d2e08b48f683159abce813f80196719beedb66900da285ee6751ed581990432c3e60ce9612228e05adc5fbe6
6
+ metadata.gz: 27ff86f49682b3bfc97c2e9f335fb1a01921b524541b7d7c5f11c283f5bd6afb50a798bcfa4748d4bbf4c457707705e2826f2c5fd4d4c431017c7f4e02bb5eb3
7
+ data.tar.gz: a109aefbd31130b58d721a92a365f3b726b4afe0854ef7a4b94872545f20332fe6f589629eb6d1952f474f30891b79d93c894204a5df503977e1b29fafac3bf7
@@ -0,0 +1,11 @@
1
+ class Array
2
+ def toggle(value)
3
+ if include?(value)
4
+ delete(value)
5
+ false
6
+ else
7
+ self << value
8
+ true
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ class Date
2
+ def to_time_range
3
+ beginning_of_day...(self + 1.day).beginning_of_day
4
+ end
5
+ end
@@ -0,0 +1,108 @@
1
+ require 'attr_extras' # gem
2
+
3
+ class Month
4
+ vattr_initialize :year, :month
5
+
6
+ class << self
7
+ def from(object)
8
+ case object
9
+ when Month then object
10
+ when String then Month.parse(object)
11
+ when Array then Month.new(object[0], object[1])
12
+ else new(object.year, object.month)
13
+ end
14
+ end
15
+
16
+ # Month.parse('201601')
17
+ # Month.parse('2016-01')
18
+ def parse(str)
19
+ date = Date.parse(str)
20
+ from(date)
21
+ rescue ArgumentError => e
22
+ if str.instance_variable_get(:@_gsub_)
23
+ raise e, str: str.instance_variable_get(:@_gsub_)
24
+ elsif e.message != 'invalid date'
25
+ raise e, str: str
26
+ end
27
+ str_gsub = str.gsub(/[^\d]/, '')
28
+ str_gsub.insert(4, '0') if str_gsub.length == 5
29
+ str_gsub += '01'
30
+ str_gsub.instance_variable_set(:@_gsub_, str_gsub)
31
+ parse(str_gsub)
32
+ end
33
+
34
+ def current
35
+ from(Date.current)
36
+ end
37
+
38
+ def now
39
+ from(Time.zone.now)
40
+ end
41
+ end
42
+
43
+ def year
44
+ Integer(@year)
45
+ end
46
+
47
+ def month
48
+ Integer(@month)
49
+ end
50
+
51
+ def first_date
52
+ Date.new(year, month, 1)
53
+ end
54
+
55
+ def last_date
56
+ Date.new(year, month, -1)
57
+ end
58
+
59
+ def first_day
60
+ first_date.day
61
+ end
62
+
63
+ def last_day
64
+ last_date.day
65
+ end
66
+
67
+ def beginning_of_month
68
+ first_date.beginning_of_day
69
+ end
70
+
71
+ def end_of_month
72
+ last_date.end_of_day
73
+ end
74
+
75
+ def date_for_day(number)
76
+ Date.new(year, month, number)
77
+ end
78
+
79
+ def to_time_range
80
+ beginning_of_month...(later.beginning_of_month)
81
+ end
82
+
83
+ def previous
84
+ self.class.from(first_date - 1)
85
+ end
86
+
87
+ def later
88
+ self.class.from(last_date + 1)
89
+ end
90
+
91
+ def to_s
92
+ "#{year}-#{month}"
93
+ end
94
+ alias_method :inspect, :to_s
95
+
96
+ def -(time)
97
+ first_date - time
98
+ end
99
+
100
+ def +(time)
101
+ first_date + time
102
+ end
103
+
104
+ include Comparable
105
+ def <=>(other)
106
+ first_date <=> Month.from(other).first_date
107
+ end
108
+ end
@@ -1,2 +1,5 @@
1
+ require_relative 'core_ext/array'
2
+ require_relative 'core_ext/date'
3
+ require_relative 'core_ext/month'
1
4
  require_relative 'core_ext/object_translation'
2
5
  require_relative 'core_ext/standard_error'
@@ -0,0 +1,193 @@
1
+ module Coaster
2
+ module SerializedProperties
3
+ class DuplicatedProperty < StandardError; end
4
+ class InvalidProperty < StandardError; end
5
+
6
+ def serialized_property_settings
7
+ @serialized_property_settings ||= {}
8
+ end
9
+
10
+ def serialized_property_setting(key)
11
+ serialized_property_settings[key.to_sym]
12
+ end
13
+
14
+ def serialized_column(serialize_column)
15
+ define_method serialize_column.to_sym do
16
+ return read_attribute(serialize_column.to_sym) if read_attribute(serialize_column.to_sym)
17
+ write_attribute(serialize_column.to_sym, {})
18
+ read_attribute(serialize_column)
19
+ end
20
+ end
21
+
22
+ def serialized_property_comment(key)
23
+ cm = serialized_property_settings[key.to_sym] &&
24
+ serialized_property_settings[key.to_sym][:comment]
25
+ cm || key.to_s
26
+ end
27
+
28
+ def serialized_property(serialize_column, key, type: nil, comment: nil, getter: nil, setter: nil, setter_callback: nil, default: nil)
29
+ raise DuplicatedProperty, "#{self.name}##{key} duplicated\n#{caller[0..5].join("\n")}" if serialized_property_settings[key.to_sym]
30
+ serialized_property_settings[key.to_sym] = {type: type, comment: comment, getter: getter, setter: setter, setter_callback: setter_callback, default: default}
31
+ _typed_serialized_property(serialize_column, key, type: type, getter: getter, setter: setter, setter_callback: setter_callback, default: default)
32
+ end
33
+
34
+ def serialized_properties(serialize_column, *keys, type: nil, getter: nil, setter: nil, setter_callback: nil, default: nil)
35
+ keys.flatten.each do |key|
36
+ key_name = key
37
+ prop_hash = {type: type, getter: getter, setter: setter, setter_callback: setter_callback, default: default}
38
+ if key.is_a? Hash
39
+ key_name = key[:key]
40
+ prop_hash = {type: type, getter: getter, setter: setter, setter_callback: setter_callback, default: default}.merge(key)
41
+ prop_hash.delete(:key)
42
+ end
43
+ serialized_property(serialize_column, key_name, prop_hash)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def _typed_serialized_property(serialize_column, key, type: nil, getter: nil, setter: nil, setter_callback: nil, default: nil)
50
+ case type
51
+ when String then
52
+ # String은 나중에 eval해서 가져옴,
53
+ # type에서 다른 객체를 참조할 경우, 순환참조가 발생할 수 있기 때문에
54
+ Rails.configuration.after_initialize {
55
+ if type.is_a?(String)
56
+ begin
57
+ type = eval(type)
58
+ raise InvalidProperty, "#{self.name}##{key} type string is return string #{type}" if type.is_a?(String)
59
+ rescue InvalidProperty => e
60
+ raise
61
+ rescue => e
62
+ raise InvalidProperty, "#{self.name}##{key} eval failed: type:[#{type}] [#{e.class.name}] #{e.message}"
63
+ end
64
+ serialized_property_setting(key.to_sym)[:type] = type
65
+ _typed_serialized_property serialize_column, key, type: type, getter: getter, setter: setter, setter_callback: setter_callback, default: default
66
+ end
67
+ }
68
+ when Array then
69
+ _define_serialized_property serialize_column, key,
70
+ setter: proc { |val|
71
+ raise InvalidProperty, "#{self.name}##{key} must be one of #{type}" unless type.include?(val)
72
+ val
73
+ },
74
+ getter: proc { |val|
75
+ type.include?(val) ? val : nil
76
+ }
77
+ else
78
+ if type == Time
79
+ _define_serialized_property serialize_column, key,
80
+ getter: Proc.new { |val| val.nil? ? nil : Time.zone.parse(val) },
81
+ setter: Proc.new { |val| val.is_a?(Time) ? val.to_s(:default_tz) : nil}
82
+ elsif type == Integer
83
+ _define_serialized_property serialize_column, key,
84
+ setter: proc { |val|
85
+ val = val.blank? ? nil : Integer(val)
86
+ val = setter.call(val) if setter
87
+ val
88
+ }
89
+ elsif type == Array
90
+ _define_serialized_property(serialize_column, key, default: [])
91
+ elsif type && type < ActiveRecord::Base
92
+ _define_serialized_property serialize_column, "#{key}_id"
93
+
94
+ define_method key.to_sym do
95
+ instance_val = instance_variable_get("@#{key}".to_sym)
96
+ return instance_val if instance_val
97
+ key_id = send("#{key}_id".to_sym)
98
+ if key_id.nil?
99
+ instance_val = nil
100
+ else
101
+ instance_val = type.find(key_id) rescue nil
102
+ instance_variable_set("@#{key}".to_sym, instance_val)
103
+ end
104
+ instance_val = getter.call(instance_val) if getter
105
+ instance_val
106
+ end
107
+
108
+ define_method "#{key}=".to_sym do |val|
109
+ val = setter.call(val) if setter
110
+
111
+ if val.nil?
112
+ instance_variable_set("@#{key}".to_sym, nil)
113
+ send("#{key}_id=".to_sym, nil)
114
+ else
115
+ unless val.is_a?(type)
116
+ raise ActiveRecord::AssociationTypeMismatch, "#{type}(##{type.object_id}) expected, got #{val.class.name}(#{val.class.object_id})"
117
+ end
118
+ instance_variable_set("@#{key}".to_sym, val)
119
+ send("#{key}_id=".to_sym, (Integer(val.id) rescue val.id))
120
+ end
121
+
122
+ if setter_callback
123
+ setter_callback.call(val)
124
+ else
125
+ val
126
+ end
127
+ end
128
+ else
129
+ _define_serialized_property serialize_column, key, getter: getter, setter: setter, setter_callback: setter_callback, default: default
130
+ end
131
+ end
132
+ end
133
+
134
+ def _define_serialized_property(serialize_column, key, getter: nil, setter: nil, setter_callback: nil, default: nil)
135
+ if default
136
+ if getter
137
+ define_method key.to_sym do
138
+ hsh = send(serialize_column.to_sym)
139
+ hsh[key.to_s] ||= default.dup
140
+ getter.call(hsh[key.to_s])
141
+ end
142
+ else
143
+ define_method key.to_sym do
144
+ hsh = send(serialize_column.to_sym)
145
+ hsh[key.to_s] ||= default.dup
146
+ end
147
+ end
148
+ else
149
+ if getter
150
+ define_method key.to_sym do
151
+ hsh = send(serialize_column.to_sym)
152
+ getter.call(hsh[key.to_s])
153
+ end
154
+ else
155
+ define_method key.to_sym do
156
+ hsh = send(serialize_column.to_sym)
157
+ hsh[key.to_s]
158
+ end
159
+ end
160
+ end
161
+
162
+ if setter
163
+ define_method "#{key}_without_callback=".to_sym do |val|
164
+ if val.nil?
165
+ send(serialize_column.to_sym).delete(key.to_s)
166
+ else
167
+ val = setter.call(val) if setter
168
+ send(serialize_column.to_sym)[key.to_s] = val
169
+ end
170
+ end
171
+ else
172
+ define_method "#{key}_without_callback=".to_sym do |val|
173
+ if val.nil?
174
+ send(serialize_column.to_sym).delete(key.to_s)
175
+ else
176
+ send(serialize_column.to_sym)[key.to_s] = val
177
+ end
178
+ end
179
+ end
180
+
181
+ if setter_callback
182
+ define_method "#{key}=".to_sym do |val|
183
+ send("#{key}_without_callback=".to_sym, val)
184
+ setter_callback.call(val)
185
+ end
186
+ else
187
+ define_method "#{key}=".to_sym do |val|
188
+ send("#{key}_without_callback=".to_sym, val)
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
@@ -1,3 +1,3 @@
1
1
  module Coaster
2
- VERSION = '0.4.7'
2
+ VERSION = '0.5.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coaster
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.7
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - buzz jung
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-14 00:00:00.000000000 Z
11
+ date: 2017-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -64,6 +64,20 @@ dependencies:
64
64
  - - "<"
65
65
  - !ruby/object:Gem::Version
66
66
  version: '8.0'
67
+ - !ruby/object:Gem::Dependency
68
+ name: attr_extras
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ type: :runtime
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
67
81
  - !ruby/object:Gem::Dependency
68
82
  name: bundler
69
83
  requirement: !ruby/object:Gem::Requirement
@@ -188,9 +202,13 @@ files:
188
202
  - lib/coaster.rb
189
203
  - lib/coaster/backtrace_cleaner.rb
190
204
  - lib/coaster/core_ext.rb
205
+ - lib/coaster/core_ext/array.rb
206
+ - lib/coaster/core_ext/date.rb
207
+ - lib/coaster/core_ext/month.rb
191
208
  - lib/coaster/core_ext/object_translation.rb
192
209
  - lib/coaster/core_ext/standard_error.rb
193
210
  - lib/coaster/core_ext/standard_error/raven.rb
211
+ - lib/coaster/serialized_properties.rb
194
212
  - lib/coaster/version.rb
195
213
  - test/locales/en.yml
196
214
  - test/test_helper.rb