setsumei 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in setsumei.gemspec
4
+ gemspec
@@ -0,0 +1,4 @@
1
+ Setsumei
2
+ --------
3
+
4
+ Api description tool to build ruby DSL's from JSON data.
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,2 @@
1
+ require 'setsumei/describable'
2
+ require 'setsumei/build'
@@ -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
@@ -0,0 +1,3 @@
1
+ module Setsumei
2
+ VERSION = "0.0.1"
3
+ end
@@ -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