frenchy 0.4.0 → 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: 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