setsumei 0.0.1
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.
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/README.md +4 -0
- data/Rakefile +2 -0
- data/lib/setsumei.rb +2 -0
- data/lib/setsumei/build.rb +21 -0
- data/lib/setsumei/build/key.rb +28 -0
- data/lib/setsumei/describable.rb +80 -0
- data/lib/setsumei/describable/boolean_attribute.rb +34 -0
- data/lib/setsumei/describable/collection.rb +20 -0
- data/lib/setsumei/describable/float_attribute.rb +34 -0
- data/lib/setsumei/describable/int_attribute.rb +33 -0
- data/lib/setsumei/describable/object_attribute.rb +41 -0
- data/lib/setsumei/describable/string_attribute.rb +33 -0
- data/lib/setsumei/version.rb +3 -0
- data/setsumei.gemspec +24 -0
- data/spec/setsumei/build/key_spec.rb +88 -0
- data/spec/setsumei/build_spec.rb +44 -0
- data/spec/setsumei/describable/boolean_attribute_spec.rb +88 -0
- data/spec/setsumei/describable/collection_spec.rb +108 -0
- data/spec/setsumei/describable/float_attribute_spec.rb +86 -0
- data/spec/setsumei/describable/int_attribute_spec.rb +87 -0
- data/spec/setsumei/describable/object_attribute_spec.rb +105 -0
- data/spec/setsumei/describable/string_attribute_spec.rb +92 -0
- data/spec/setsumei/describable_spec.rb +132 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/be_an_attribute_of_type_matcher.rb +5 -0
- data/spec/support/shared_examples/attribute_type_creation.rb +13 -0
- metadata +139 -0
data/.rspec
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
data/lib/setsumei.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'setsumei/build/key'
|
2
|
+
|
3
|
+
module Setsumei
|
4
|
+
module Build
|
5
|
+
def Build.a(klass,options = {})
|
6
|
+
inform_developer "#{klass} should be able to list its attributes" unless klass.respond_to? :defined_attributes
|
7
|
+
inform_developer "wrong number of arguments, options must include from: data }" unless options.keys.include? :from
|
8
|
+
|
9
|
+
klass.new.tap do |object|
|
10
|
+
klass.defined_attributes.each do |_,attribute|
|
11
|
+
attribute.set_value_on object, from_value_in: options[:from]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def self.inform_developer(message)
|
18
|
+
raise ArgumentError.new message
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Setsumei
|
2
|
+
module Build
|
3
|
+
class Key
|
4
|
+
def Key.for(name,options = { given: [name] } )
|
5
|
+
possible_keys = options[:given]
|
6
|
+
lower_camel_case(name,possible_keys) || at_symbol_case(name,possible_keys) || upper_camel_case(name,possible_keys)
|
7
|
+
end
|
8
|
+
def Key.lower_camel_case name, keys = nil
|
9
|
+
lower_camel_case = name.to_s.gsub(/_[a-zA-Z]/) { |a| a[1].upcase }
|
10
|
+
return_if lower_camel_case, in: keys
|
11
|
+
end
|
12
|
+
def Key.at_symbol_case name, keys = nil
|
13
|
+
at_symbol_case = "@" + lower_camel_case(name)
|
14
|
+
return_if at_symbol_case, in: keys
|
15
|
+
end
|
16
|
+
def Key.upper_camel_case name, keys = nil
|
17
|
+
lower_camel_case = self.lower_camel_case(name)
|
18
|
+
upper_camel_case = lower_camel_case[0].upcase + lower_camel_case[1..-1]
|
19
|
+
return_if upper_camel_case, in: keys
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def self.return_if value, options = { in: [] }
|
24
|
+
(options[:in] || [value]).select { |possible| possible == value }.first
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'setsumei/describable/boolean_attribute'
|
2
|
+
require 'setsumei/describable/string_attribute'
|
3
|
+
require 'setsumei/describable/float_attribute'
|
4
|
+
require 'setsumei/describable/int_attribute'
|
5
|
+
require 'setsumei/describable/object_attribute'
|
6
|
+
require 'setsumei/describable/collection'
|
7
|
+
|
8
|
+
module Setsumei
|
9
|
+
module Describable
|
10
|
+
|
11
|
+
def Describable.included(other)
|
12
|
+
other.extend DescriptionMethods
|
13
|
+
end
|
14
|
+
|
15
|
+
module DescriptionMethods
|
16
|
+
|
17
|
+
def defined_attributes
|
18
|
+
_defined_attributes.dup
|
19
|
+
end
|
20
|
+
|
21
|
+
def define field_name, options = {}
|
22
|
+
_defined_attributes[field_name] = attribute_type(options[:as_a]).named field_name, options
|
23
|
+
attr_accessor field_name
|
24
|
+
end
|
25
|
+
|
26
|
+
def collection_of klass, options = {}
|
27
|
+
self.class_eval do
|
28
|
+
include Enumerable
|
29
|
+
include Comparable
|
30
|
+
|
31
|
+
def each(*args,&block)
|
32
|
+
_internal_collection.each(*args,&block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def include? value
|
36
|
+
_internal_collection.include? value
|
37
|
+
end
|
38
|
+
|
39
|
+
def <<(value)
|
40
|
+
_internal_collection << value
|
41
|
+
end
|
42
|
+
|
43
|
+
def [](value)
|
44
|
+
_internal_collection[value]
|
45
|
+
end
|
46
|
+
|
47
|
+
def []=(index,value)
|
48
|
+
_internal_collection[index] = value
|
49
|
+
end
|
50
|
+
|
51
|
+
def <=>(other)
|
52
|
+
_internal_collection <=> other || super
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def _internal_collection
|
57
|
+
@_internal_collection ||= []
|
58
|
+
end
|
59
|
+
end
|
60
|
+
_defined_attributes[:_self] = Collection.of klass,options
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def _defined_attributes
|
65
|
+
(@_defined_attributes ||= {})
|
66
|
+
end
|
67
|
+
def attribute_type(type)
|
68
|
+
case type
|
69
|
+
when :boolean then BooleanAttribute
|
70
|
+
when :string then StringAttribute
|
71
|
+
when nil then StringAttribute
|
72
|
+
when :float then FloatAttribute
|
73
|
+
when :int then IntAttribute
|
74
|
+
else
|
75
|
+
ObjectAttribute if type.is_a?(Class)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Setsumei
|
2
|
+
module Describable
|
3
|
+
class BooleanAttribute
|
4
|
+
|
5
|
+
def BooleanAttribute.named(name, options = {})
|
6
|
+
new.tap do |attribute|
|
7
|
+
attribute.name = name
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_accessor :name
|
12
|
+
|
13
|
+
def is_an_attribute_of_type?(type)
|
14
|
+
type == :boolean || type == self.class
|
15
|
+
end
|
16
|
+
|
17
|
+
def value_for(pre_type_cast_value)
|
18
|
+
pre_type_cast_value.to_s.downcase == "true" || pre_type_cast_value.to_s == "1"
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_value_on(object, options)
|
22
|
+
object.send accessor, value_from_hash(options[:from_value_in])
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def accessor
|
27
|
+
:"#{name}="
|
28
|
+
end
|
29
|
+
def value_from_hash(hash)
|
30
|
+
value_for hash[ Build::Key.for name, given: hash.keys ]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Setsumei
|
2
|
+
module Describable
|
3
|
+
class Collection
|
4
|
+
def Collection.of(klass,options = {})
|
5
|
+
new.tap do |collection|
|
6
|
+
collection.klass = klass
|
7
|
+
collection.options = options
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_accessor :klass, :options
|
12
|
+
|
13
|
+
def set_value_on(object, options = {})
|
14
|
+
[options[:from_value_in][Build::Key.for((self.options[:within] || klass), given: options[:from_value_in].keys)]].flatten(1).each do |data|
|
15
|
+
object << Build.a(klass, from: data)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Setsumei
|
2
|
+
module Describable
|
3
|
+
class FloatAttribute
|
4
|
+
|
5
|
+
def FloatAttribute.named(name, options = {})
|
6
|
+
new.tap do |attribute|
|
7
|
+
attribute.name = name
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_accessor :name
|
12
|
+
|
13
|
+
def is_an_attribute_of_type?(type)
|
14
|
+
type == :float || type == self.class
|
15
|
+
end
|
16
|
+
|
17
|
+
def value_for(pre_type_cast_value)
|
18
|
+
pre_type_cast_value.to_f
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_value_on(object, options)
|
22
|
+
object.send accessor, value_from_hash(options[:from_value_in])
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def accessor
|
27
|
+
:"#{name}="
|
28
|
+
end
|
29
|
+
def value_from_hash(hash)
|
30
|
+
value_for hash[ Build::Key.for name, given: hash.keys ]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Setsumei
|
2
|
+
module Describable
|
3
|
+
class IntAttribute
|
4
|
+
def IntAttribute.named(name, options = {})
|
5
|
+
new.tap do |attribute|
|
6
|
+
attribute.name = name
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :name
|
11
|
+
|
12
|
+
def is_an_attribute_of_type?(type)
|
13
|
+
type == :int || type == self.class
|
14
|
+
end
|
15
|
+
|
16
|
+
def value_for(pre_type_cast_value)
|
17
|
+
pre_type_cast_value.to_f.round
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_value_on(object, options)
|
21
|
+
object.send accessor, value_from_hash(options[:from_value_in])
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def accessor
|
26
|
+
:"#{name}="
|
27
|
+
end
|
28
|
+
def value_from_hash(hash)
|
29
|
+
value_for hash[ Build::Key.for name, given: hash.keys ]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Setsumei
|
2
|
+
module Describable
|
3
|
+
class ObjectAttribute
|
4
|
+
|
5
|
+
def ObjectAttribute.named(name,options = {})
|
6
|
+
raise ArgumentError.new("you must specify what the object is") unless options.has_key? :as_a
|
7
|
+
new.tap do |attribute|
|
8
|
+
attribute.name = name
|
9
|
+
attribute.klass = options[:as_a]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :name, :klass
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
self.klass = Object
|
17
|
+
end
|
18
|
+
|
19
|
+
def value_for(data)
|
20
|
+
return nil if data.nil? || data.empty?
|
21
|
+
Build.a self.klass, from: data
|
22
|
+
end
|
23
|
+
|
24
|
+
def is_an_attribute_of_type?(type)
|
25
|
+
type == :object || type == self.class || type == self.klass
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_value_on(object, options)
|
29
|
+
object.send accessor, value_from_hash(options[:from_value_in])
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def accessor
|
34
|
+
:"#{name}="
|
35
|
+
end
|
36
|
+
def value_from_hash(hash)
|
37
|
+
value_for hash[ Build::Key.for name, given: hash.keys ]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Setsumei
|
2
|
+
module Describable
|
3
|
+
class StringAttribute
|
4
|
+
def StringAttribute.named(name,options = {})
|
5
|
+
new.tap do |attribute|
|
6
|
+
attribute.name = name
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :name
|
11
|
+
|
12
|
+
def is_an_attribute_of_type?(type)
|
13
|
+
type == :string || type == self.class
|
14
|
+
end
|
15
|
+
|
16
|
+
def value_for(pre_type_cast_value)
|
17
|
+
pre_type_cast_value.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_value_on(object, options)
|
21
|
+
object.send accessor, value_from_hash(options[:from_value_in])
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def accessor
|
26
|
+
:"#{name}="
|
27
|
+
end
|
28
|
+
def value_from_hash(hash)
|
29
|
+
value_for hash[ Build::Key.for name, given: hash.keys ]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/setsumei.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "setsumei/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "setsumei"
|
7
|
+
s.version = Setsumei::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Jon Rowe"]
|
10
|
+
s.email = ["hello@jonrowe.co.uk"]
|
11
|
+
s.homepage = "https://github.com/JonRowe/setsumei"
|
12
|
+
s.summary = %q{A tool for describing API's as ruby objects}
|
13
|
+
s.description = %q{A tool for describing API's as ruby objects. Currently supports building these objects from JSON}
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_runtime_dependency 'json'
|
21
|
+
s.add_development_dependency 'rspec'
|
22
|
+
s.add_development_dependency 'autotest-standalone'
|
23
|
+
s.add_development_dependency 'ruby-debug19'
|
24
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Setsumei
|
4
|
+
module Build
|
5
|
+
describe Key do
|
6
|
+
describe ".for name, given: hash_keys" do
|
7
|
+
let(:hash_keys) { ["otherAttribute","@anotherAttribute","Array","Object"] }
|
8
|
+
|
9
|
+
subject { Key.for :attribute_name, given: hash_keys }
|
10
|
+
|
11
|
+
specify do
|
12
|
+
hash_keys.concat ["AttributeName", "attributeName", "@attributeName"]
|
13
|
+
subject.should == "attributeName"
|
14
|
+
end
|
15
|
+
|
16
|
+
specify do
|
17
|
+
hash_keys.concat ["AttributeName", "@attributeName"]
|
18
|
+
subject.should == "@attributeName"
|
19
|
+
end
|
20
|
+
|
21
|
+
specify do
|
22
|
+
hash_keys.concat ["AttributeName"]
|
23
|
+
subject.should == "AttributeName"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "lower_camel_case(name,keys)" do
|
28
|
+
let(:keys) { [] }
|
29
|
+
|
30
|
+
subject { Key.lower_camel_case :attribute_name, keys }
|
31
|
+
|
32
|
+
it "should return lower camelcase named when keys contain name" do
|
33
|
+
keys << "attributeName"
|
34
|
+
subject.should == "attributeName"
|
35
|
+
end
|
36
|
+
it "should return nil when keys do not contain name" do
|
37
|
+
subject.should be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
context "keys are ommited" do
|
41
|
+
it "should return lower camelcase name" do
|
42
|
+
Key.lower_camel_case(:attribute_name).should == "attributeName"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "upper_camel_case(name,keys)" do
|
48
|
+
let(:keys) { [] }
|
49
|
+
|
50
|
+
subject { Key.upper_camel_case :attribute_name, keys }
|
51
|
+
|
52
|
+
it "should return upper camelcase named when keys contain name" do
|
53
|
+
keys << "AttributeName"
|
54
|
+
subject.should == "AttributeName"
|
55
|
+
end
|
56
|
+
it "should return nil when keys do not contain name" do
|
57
|
+
subject.should be_nil
|
58
|
+
end
|
59
|
+
|
60
|
+
context "keys are ommited" do
|
61
|
+
it "should return upper camelcase name" do
|
62
|
+
Key.upper_camel_case(:attribute_name).should == "AttributeName"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "at_symbol_case(name,keys)" do
|
68
|
+
let(:keys) { [] }
|
69
|
+
|
70
|
+
subject { Key.at_symbol_case :attribute_name, keys }
|
71
|
+
|
72
|
+
it "should return symbol case named when keys contain name" do
|
73
|
+
keys << "@attributeName"
|
74
|
+
subject.should == "@attributeName"
|
75
|
+
end
|
76
|
+
it "should return nil when keys do not contain name" do
|
77
|
+
subject.should be_nil
|
78
|
+
end
|
79
|
+
|
80
|
+
context "keys are ommited" do
|
81
|
+
it "should return at symbol case" do
|
82
|
+
Key.at_symbol_case(:attribute_name).should == "@attributeName"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|