frenchy 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bbd873ca7bf47ce23e6e60450167777221a970c4
4
- data.tar.gz: b482ca20c727d4ebad679da013405e15e260bd37
3
+ metadata.gz: c053d86535fc11bfb4789c95b7a3207089b81a3e
4
+ data.tar.gz: 99f313562478d7607816b095e176fef88d2fdeed
5
5
  SHA512:
6
- metadata.gz: e477ae25b9c358cf9ad06d3b1816720ef0da7b81666cda78c0780d9275dd9fabb8592b492a2a251e1e54ed49e8b1146606e431aedae18f42b688f4e9e246116c
7
- data.tar.gz: aa04396f718b9523f060e6d29913c2c8601466f580fa9de1855bd6e3f0067d9d6c8f9dd69372edae0b21e01c83fea219065f27b4dbf5f26f3368e112118bd713
6
+ metadata.gz: 8da2c669175476f793dad871f7e737e1b65b89a4c98dca7582e0d23b3f9f63633ad56c2e343cacef2452acc6d53755d6e8bd7d505f4a0d813722747494253f5f
7
+ data.tar.gz: 77ef9f74818af9c594d721f270ac1fcde31433e43204a636a979426f4a9ea7f7995e0fea7601ccda015df669fc642b74f37f0995f2bf3ef13b6f668bbd3d64a9
@@ -2,6 +2,7 @@ require "frenchy/core_ext"
2
2
 
3
3
  require "frenchy/client"
4
4
  require "frenchy/collection"
5
+ require "frenchy/enum"
5
6
  require "frenchy/error"
6
7
  require "frenchy/instrumentation"
7
8
  require "frenchy/model"
@@ -0,0 +1,71 @@
1
+ module Frenchy
2
+ module Enum
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+
6
+ base.class_eval do
7
+ @enums = {}
8
+ @default = nil
9
+ end
10
+ end
11
+
12
+ attr_accessor :name, :tag
13
+
14
+ def initialize(attrs={})
15
+ attrs.each do |k, v|
16
+ send("#{k}=", v) if respond_to?("#{k}=")
17
+ end
18
+ end
19
+
20
+ def inspect
21
+ "\#<#{self.class.name}::#{name}=#{tag}>"
22
+ end
23
+
24
+ def to_i
25
+ tag
26
+ end
27
+
28
+ def to_str
29
+ to_s
30
+ end
31
+
32
+ def to_sym
33
+ name
34
+ end
35
+
36
+ def to_s
37
+ name.to_s.underscore
38
+ end
39
+
40
+ def ==(other)
41
+ (other.is_a?(Symbol) && (name == other)) ||
42
+ (other.respond_to?(:to_i) && (other.to_i == tag)) ||
43
+ (other.respond_to?(:to_s) && (other.to_s == to_s || other.to_s == name.to_s)) ||
44
+ super
45
+ end
46
+
47
+ module ClassMethods
48
+ def define(name, tag, options={})
49
+ name = name.to_sym
50
+ tag = tag.to_i
51
+ options.stringify_keys!
52
+
53
+ enum = new(name: name, tag: tag)
54
+ const_set(name, enum)
55
+ @enums[tag] = enum
56
+
57
+ if options["default"]
58
+ @default = tag
59
+ end
60
+ end
61
+
62
+ def default
63
+ @enums[@default]
64
+ end
65
+
66
+ def find(tag)
67
+ @enums[tag.to_i] || default
68
+ end
69
+ end
70
+ end
71
+ end
@@ -77,6 +77,15 @@ module Frenchy
77
77
  klass.class_eval(&block)
78
78
  end
79
79
 
80
+ # Macro to add an enum type
81
+ def enum(name, &block)
82
+ klass = Class.new(self) do
83
+ include Frenchy::Enum
84
+ end
85
+ const_set(name.to_s.camelize, klass)
86
+ klass.class_eval(&block)
87
+ end
88
+
80
89
  # Macro to create a subtype and associated field
81
90
  def embed(name, options={}, &block)
82
91
  type(name, &block)
@@ -88,6 +97,11 @@ module Frenchy
88
97
  name = name.to_s
89
98
  options.stringify_keys!
90
99
 
100
+ if options["enum"]
101
+ options["type"] = "enum"
102
+ options["class_name"] ||= options["enum"].to_s.camelize
103
+ end
104
+
91
105
  type = (options["type"] || "string").to_s
92
106
  aliases = (options["aliases"] || [])
93
107
 
@@ -160,6 +174,15 @@ module Frenchy
160
174
  set(name, Hash[v])
161
175
  end
162
176
 
177
+ when "enum"
178
+ # Resolve the class name
179
+ klass = const_get(options["class_name"])
180
+
181
+ # Convert value to enum class
182
+ define_method("#{name}=") do |v|
183
+ set(name, klass.find(v.to_i))
184
+ end
185
+
163
186
  else
164
187
  # Unknown types have their type constantized and initialized with the value. This
165
188
  # allows us to support things like other Frenchy::Model classes, ActiveRecord models, etc.
@@ -1,3 +1,3 @@
1
1
  module Frenchy
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -0,0 +1,114 @@
1
+ require "spec_helper"
2
+
3
+ class SimpleEnum
4
+ include Frenchy::Enum
5
+
6
+ define :NONE, 0
7
+ define :PARTIAL, 1
8
+ define :FULL, 2
9
+ end
10
+
11
+ class EnumWithDefault
12
+ include Frenchy::Enum
13
+
14
+ define :NONE, 0
15
+ define :PARTIAL_SUPPORT, 1
16
+ define :FULL_SUPPORT, 2, default: true
17
+ end
18
+
19
+ describe Frenchy::Enum do
20
+ describe ".default" do
21
+ it "returns the default if set" do
22
+ e = EnumWithDefault.default
23
+ expect(e).to eql(EnumWithDefault::FULL_SUPPORT)
24
+ end
25
+
26
+ it "returns nil if not set" do
27
+ e = SimpleEnum.default
28
+ expect(e).to eql nil
29
+ end
30
+ end
31
+
32
+ describe ".find" do
33
+ it "finds by tag" do
34
+ e = SimpleEnum.find(1)
35
+ expect(e).to be_an_instance_of(SimpleEnum)
36
+ expect(e.tag).to eql(1)
37
+ expect(e.name).to eql(:PARTIAL)
38
+ end
39
+
40
+ it "returns nil when no match is found" do
41
+ e = SimpleEnum.find(5)
42
+ expect(e).to eql(nil)
43
+ end
44
+
45
+ it "returns default when no match is found and a default is declared" do
46
+ e = EnumWithDefault.find(5)
47
+ expect(e).to be_an_instance_of(EnumWithDefault)
48
+ expect(e.tag).to eql(2)
49
+ expect(e.name).to eql(:FULL_SUPPORT)
50
+ end
51
+ end
52
+
53
+ describe "constants" do
54
+ it "declares constants" do
55
+ e = SimpleEnum::PARTIAL
56
+ expect(e).to be_an_instance_of(SimpleEnum)
57
+ expect(e.tag).to eql(1)
58
+ expect(e.name).to eql(:PARTIAL)
59
+
60
+ e = SimpleEnum::FULL
61
+ expect(e).to be_an_instance_of(SimpleEnum)
62
+ expect(e.tag).to eql(2)
63
+ expect(e.name).to eql(:FULL)
64
+ end
65
+ end
66
+
67
+ describe "model" do
68
+ it "describes itself" do
69
+ e = SimpleEnum::FULL
70
+ expect(e.inspect).to eql "\#<SimpleEnum::FULL=2>"
71
+ end
72
+
73
+ it "== compares equality" do
74
+ e = SimpleEnum::FULL
75
+ e2 = EnumWithDefault::FULL_SUPPORT
76
+ f = SimpleEnum::PARTIAL
77
+
78
+ # Separate reference
79
+ expect(e == SimpleEnum::FULL).to eql(true)
80
+
81
+ # Comparison by enum
82
+ expect(e == e).to eql(true)
83
+
84
+ # Comparison across enum types
85
+ expect(e == e2).to eql(true)
86
+ expect(e == f).to eql(false)
87
+
88
+ # Comparison by tag
89
+ expect(e == 2).to eql(true)
90
+ expect(2 == e).to eql(true)
91
+
92
+ # Comparison by string
93
+ expect(e == "full").to eql(true)
94
+ expect("full" == e).to eql(true)
95
+ expect(e == "FULL").to eql(true)
96
+ expect("FULL" == e).to eql(true)
97
+ end
98
+
99
+ it "#to_i returns the tag" do
100
+ e = SimpleEnum::FULL
101
+ expect(e.to_i).to eql(2)
102
+ end
103
+
104
+ it "#to_s returns a lowercase name" do
105
+ e = SimpleEnum::FULL
106
+ expect(e.to_s).to eql("full")
107
+ end
108
+
109
+ it "#to_s returns underscore names" do
110
+ e = EnumWithDefault::FULL_SUPPORT
111
+ expect(e.to_s).to eql("full_support")
112
+ end
113
+ end
114
+ end
@@ -23,6 +23,12 @@ end
23
23
  class Box
24
24
  include Frenchy::Model
25
25
 
26
+ enum :priority do
27
+ define :NORMAL, 0, default: true
28
+ define :PRIORITY, 1
29
+ define :EXPRESS, 2
30
+ end
31
+
26
32
  class SubclassItem
27
33
  include Frenchy::Model
28
34
 
@@ -53,6 +59,9 @@ class Box
53
59
  field :special, type: "special_item", class_name: "SuperSpecialItem"
54
60
  field :subclass, type: "subclass_item"
55
61
  field :subtype, type: "subtype_item"
62
+
63
+ field :priority, enum: "priority"
64
+ field :other_priority, enum: "priority", default: Priority::NORMAL
56
65
  end
57
66
 
58
67
  class SimpleModelDecorator
@@ -234,6 +243,28 @@ describe Frenchy::Model do
234
243
  end
235
244
  end
236
245
 
246
+ describe "enum" do
247
+ it "defaults to the default" do
248
+ v = Box.new
249
+ expect(v.priority).to eql(nil)
250
+ expect(v.other_priority).to eql(Box::Priority::NORMAL)
251
+ end
252
+
253
+ it "accepts fixnums" do
254
+ v = Box.new(priority: 2)
255
+ expect(v.priority).to eql(Box::Priority::EXPRESS)
256
+ expect(v.priority.to_i).to eql(2)
257
+ expect(v.priority.to_s).to eql("express")
258
+ end
259
+
260
+ it "accepts enums" do
261
+ v = Box.new(priority: Box::Priority::PRIORITY)
262
+ expect(v.priority).to eql(Box::Priority::PRIORITY)
263
+ expect(v.priority.to_i).to eql(1)
264
+ expect(v.priority.to_s).to eql("priority")
265
+ end
266
+ end
267
+
237
268
  describe "model relationships" do
238
269
  it "establishes single model relationships" do
239
270
  v = Box.new(item: {id: 1}).item
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: frenchy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Coene
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-25 00:00:00.000000000 Z
11
+ date: 2016-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -142,6 +142,7 @@ files:
142
142
  - lib/frenchy/client.rb
143
143
  - lib/frenchy/collection.rb
144
144
  - lib/frenchy/core_ext.rb
145
+ - lib/frenchy/enum.rb
145
146
  - lib/frenchy/error.rb
146
147
  - lib/frenchy/instrumentation.rb
147
148
  - lib/frenchy/model.rb
@@ -152,6 +153,7 @@ files:
152
153
  - spec/lib/frenchy/client_spec.rb
153
154
  - spec/lib/frenchy/collection_spec.rb
154
155
  - spec/lib/frenchy/core_ext_spec.rb
156
+ - spec/lib/frenchy/enum_spec.rb
155
157
  - spec/lib/frenchy/error_spec.rb
156
158
  - spec/lib/frenchy/model_spec.rb
157
159
  - spec/lib/frenchy/request_spec.rb
@@ -187,6 +189,7 @@ test_files:
187
189
  - spec/lib/frenchy/client_spec.rb
188
190
  - spec/lib/frenchy/collection_spec.rb
189
191
  - spec/lib/frenchy/core_ext_spec.rb
192
+ - spec/lib/frenchy/enum_spec.rb
190
193
  - spec/lib/frenchy/error_spec.rb
191
194
  - spec/lib/frenchy/model_spec.rb
192
195
  - spec/lib/frenchy/request_spec.rb