elmas 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2ad5e2f6e04bc4bbb0d56e770fae4bd99ada5fca
4
+ data.tar.gz: 37bbce0d0945e16dbfd38ec787cb0280324b183e
5
+ SHA512:
6
+ metadata.gz: 8019c2c6edbf2e50598dd5d671f9390e1cd5c89bcc923df4f62018598be77cdfddb1647082b6ff1695d3c5ff68b9cf4f3d135e5472c8c383641577890fcefa6d
7
+ data.tar.gz: f58ab43a5cb1884ec87acad7725dd3d10ce6bf900c9d68e0cff88c71581cde7d9d9eb6ba6a7c69e46ff341d62726d78b96b46db857e612432090051eac739f81
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .DS_Store
11
+ .env
12
+ .log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,52 @@
1
+ Documentation:
2
+ Enabled: false
3
+
4
+ StringLiterals:
5
+ EnforcedStyle: double_quotes
6
+
7
+ AllCops:
8
+ Include:
9
+ - '**/Rakefile'
10
+ - '**/config.ru'
11
+ Exclude:
12
+ - 'db/**/*'
13
+ - 'tmp/**/*'
14
+ - 'vendor/**/*'
15
+ - 'bin/**/*'
16
+ - 'log/**/*'
17
+ - 'spec/**/*'
18
+ - 'config/**/*'
19
+ RunRailsCops: true
20
+
21
+ Metrics/AbcSize:
22
+ Max: 30
23
+ Metrics/BlockNesting:
24
+ Max: 3
25
+ Metrics/ClassLength:
26
+ CountComments: false # count full line comments?
27
+ Max: 100
28
+ Metrics/CyclomaticComplexity:
29
+ Max: 6
30
+ Metrics/LineLength:
31
+ Max: 150
32
+ AllowURI: true
33
+ URISchemes:
34
+ - http
35
+ - https
36
+
37
+ Metrics/MethodLength:
38
+ CountComments: false # count full line comments?
39
+ Max: 13
40
+
41
+ Metrics/ParameterLists:
42
+ Max: 5
43
+ CountKeywordArgs: true
44
+
45
+ Metrics/PerceivedComplexity:
46
+ Max: 7
47
+ Style/PerlBackrefs:
48
+ Enabled: false
49
+ Lint/AmbiguousOperator:
50
+ Enabled: false
51
+ Rails/Delegate:
52
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.1
4
+ cache: bundler
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in elmas.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,11 @@
1
+ guard :rspec, cmd: 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { "spec" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
6
+
7
+ guard :rubocop, all_on_start: false, cli: ['--format', 'clang', '--rails'] do
8
+ watch(%r{^spec/.+_spec\.rb$})
9
+ watch(%r{^lib/(.+)\.rb$})
10
+ watch('spec/spec_helper.rb')
11
+ end
data/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # Elmas
2
+
3
+ Elmas means diamond, but in this case it's an API wrapper for [Exact Online](https://developers.exactonline.com/).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'elmas'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install elmas
20
+
21
+ ## Usage
22
+
23
+ You have to have an Exact Online account and an app setup to connect with.
24
+
25
+ You have to set a few variables to make a connection possible. I'd suggest using environment variables set with [dotenv](https://github.com/bkeepers/dotenv) for that. (You can of course hardcode them, but that is not very secure :-) )
26
+
27
+
28
+ Then configure Elmas like this
29
+
30
+ ```ruby
31
+ Elmas.configure do |config|
32
+ config.client_id = ENV['CLIENT_ID']
33
+ config.client_secret = ENV['CLIENT_SECRET']
34
+ config.access_token = Elmas.authorize(ENV['EXACT_USER_NAME'], ENV['EXACT_PASSWORD']).access_token
35
+ end
36
+
37
+ #The client will now be authorized for 10 minutes,
38
+ # if there are requests the time will be reset,
39
+ # otherwise authorization should be called again.
40
+ unless Elmas.authorized?
41
+ Elmas.configure do |config|
42
+ config.access_token = Elmas.authorize(ENV['EXACT_USER_NAME'], ENV['EXACT_PASSWORD']).access_token
43
+ end
44
+ end
45
+ ```
46
+
47
+ To find a contact
48
+
49
+ ```ruby
50
+ contact = Elmas::Contact.new(id: "23445")
51
+ contact.find
52
+ # path = /crm/Contacts?$filter=ID eq guid'23445'
53
+ ```
54
+
55
+ To find a contact with specific filters
56
+ ```ruby
57
+ contact = Elmas::Contact.new(first_name: "Karel", id: "23")
58
+ contact.find_by(filters: [:first_name])
59
+ # path = /crm/Contacts?$filter=first_name eq 'Karel'
60
+ ```
61
+
62
+ To find contacts with an order and a filter
63
+ ```ruby
64
+ contact = Elmas::Contact.new(first_name: "Karel")
65
+ contact.find_by(filters: [:first_name], order_by: :first_name)
66
+ # path = /crm/Contacts?$order_by=first_name&$filter=first_name eq 'Karel'
67
+ ```
68
+
69
+ To find contacts with an order, a filter and selecting relationships
70
+ ```ruby
71
+ contact = Elmas::Contact.new(first_name: "Karel")
72
+ contact.find_by(filters: [:first_name], order_by: :first_name, select: [:invoice])
73
+ # path = /crm/Contacts?$select=invoice&$order_by=first_name&$filter=first_name eq 'Karel'
74
+ ```
75
+
76
+ So with find_by you can combine Filters, Select and OrderBy. For more information on this way of selecting data look here http://www.odata.org/
77
+ There's also a method find_all, which does a get without filters. You can however set the select and order by params.
78
+
79
+ To find all contacts
80
+ ```ruby
81
+ contact = Elmas::Contact.new
82
+ contact.find_all
83
+ # path = /crm/Contacts
84
+ ```
85
+
86
+ To find all contacts and order by first_name
87
+ ```ruby
88
+ contact = Elmas::Contact.new
89
+ contact.find_all(order_by: :first_name)
90
+ # path = /crm/Contacts?$order_by=first_name
91
+ ```
92
+
93
+ To find all contacts and select invoices and items
94
+ ```ruby
95
+ contact = Elmas::Contact.new
96
+ contact.find_all(select: [:invoice, :item])
97
+ # path = /crm/Contacts?$select=invoice,item
98
+ ```
99
+
100
+ To create a new contact
101
+
102
+ ```ruby
103
+ contact = Elmas::Contact.new(first_name: "Karel", last_name: "Appel", id: "2378712")
104
+ contact.save
105
+ ```
106
+
107
+ ###Divisions and Endpoints
108
+
109
+ Usually in the exact wrapper you need a division number, this one will be set on authorization checks (with `/Current/Me` endpoint). Sometimes you need to do a request without the division number, or even without the standard `/api/v1` endpoint. Like so:
110
+
111
+ ```ruby
112
+ response = Elmas.get('/api/oauth2/token', no_endpoint: true, no_division: true)
113
+ response = Elmas.get('/Current/Me', no_division: true)
114
+ ```
115
+
116
+ ## Development
117
+
118
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
119
+
120
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
121
+
122
+ ## Contributing
123
+
124
+ 1. Fork it ( https://github.com/[my-github-username]/elmas/fork )
125
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
126
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
127
+ 4. Push to the branch (`git push origin my-new-feature`)
128
+ 5. Create a new Pull Request
129
+
130
+ ## Testing
131
+
132
+ We use Rspec for normal unit testing. We aim for coverage above 90%. Also the current suite should succeed when you commit something.
133
+ We use Rubocop for style checking, this should also succeed before you commit anything.
134
+
135
+ We're also experimenting with Mutation testing, which alters your code to test if your specs fail when there's faulty code. This is important when you
136
+ alter a vital part of the code, make sure the mutation percentage is higher than 80%. To run a part of the code with mutant run the follwing
137
+ `mutant --include lib/elmas --require elmas --use rspec Elmas::ClassYoureWorkingOn`
138
+
139
+ To test the vital classes run this
140
+ `mutant --include lib --require elmas --use rspec Elmas::Response Elmas::Client Elmas::Utils Elmas::Resource Elmas::Request Elmas::Parser Elmas::Config`
141
+ This will take a few minutes
142
+
143
+ When you're editing code it's advised you run guard, which watches file changes and automatically runs Rspec and Rubocop.
144
+
145
+ ## Hoppinger
146
+
147
+ This gem was created by [Hoppinger](http://www.hoppinger.com)
148
+
149
+ [![forthebadge](http://forthebadge.com/images/badges/built-with-ruby.svg)](http://www.hoppinger.com)
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :rubocop do
4
+ sh "rubocop"
5
+ end
6
+
7
+ task :rspec do
8
+ sh "rspec"
9
+ end
10
+
11
+ task default: [:rubocop, :rspec]
data/bin/console ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "elmas"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ require "dotenv"
15
+ Dotenv.load
16
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/elmas.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'elmas/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "elmas"
8
+ spec.authors = ["Marthyn"]
9
+ spec.email = ["MarthynOlthof@hoppinger.nl"]
10
+
11
+ spec.summary = %q{API wrapper for Exact Online}
12
+ spec.homepage = "https://www.hoppinger.com"
13
+ spec.licenses = %w(MIT)
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
16
+ spec.require_paths = %w(lib)
17
+ spec.version = Elmas::Version.to_s
18
+
19
+ spec.add_dependency "faraday", [">= 0.8", "< 0.10"]
20
+ spec.add_dependency "mechanize", "2.6.0"
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.9"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency("rspec", "~> 3.0")
25
+ spec.add_development_dependency("simplecov")
26
+ spec.add_development_dependency("simplecov-rcov")
27
+ spec.add_development_dependency("webmock", "~> 1.6")
28
+ spec.add_development_dependency("rubycritic", "~> 1.4.0")
29
+ spec.add_development_dependency("guard-rspec")
30
+ spec.add_development_dependency("guard-rubocop")
31
+ spec.add_development_dependency("mutant-rspec")
32
+ spec.add_development_dependency("dotenv")
33
+ end
data/jenkins.sh ADDED
@@ -0,0 +1,33 @@
1
+ #!/bin/bash
2
+ export RAILS_ENV=test
3
+ export COVERAGE=true
4
+
5
+ bundle install
6
+
7
+ if [[ -d coverage ]]; then
8
+ echo "Removing old coverage report"
9
+ rm -r coverage
10
+ fi
11
+
12
+ echo "--- Check style"
13
+
14
+ rubocop
15
+
16
+ if [[ $? -ne 0 ]]; then
17
+ echo "--- Style checks failed."
18
+ exit 1
19
+ fi
20
+
21
+ echo "--- Doing a static analysis"
22
+
23
+ rubycritic app lib config
24
+
25
+ echo "--- Running RSpec"
26
+
27
+ rspec --color spec --format progress --format html --out rspec.html
28
+ rspec=$?
29
+
30
+ if [[ $rspec -ne 0 ]]; then
31
+ echo "--- Some tests have failed."
32
+ exit 1
33
+ fi
data/lib/elmas.rb ADDED
@@ -0,0 +1,33 @@
1
+ require "elmas/version"
2
+ require "elmas/api"
3
+ require "elmas/config"
4
+ require "elmas/response"
5
+ require "elmas/client"
6
+ require "elmas/log"
7
+ require "elmas/resource"
8
+ require "elmas/resources/contact"
9
+ require "elmas/resources/invoice"
10
+ require "elmas/resources/journal"
11
+ require "elmas/resources/item"
12
+ require "elmas/resources/invoice_line"
13
+ require "elmas/resources/account"
14
+
15
+ module Elmas
16
+ extend Config
17
+ extend Log
18
+
19
+ def self.client(options = {})
20
+ Elmas::Client.new(options)
21
+ end
22
+
23
+ # Delegate to Elmas::Client
24
+ def self.method_missing(method, *args, &block)
25
+ super unless client.respond_to?(method)
26
+ client.send(method, *args, &block)
27
+ end
28
+
29
+ # Delegate to Elmas::Client
30
+ def self.respond_to?(method, include_all = false)
31
+ client.respond_to?(method, include_all) || super
32
+ end
33
+ end
data/lib/elmas/api.rb ADDED
@@ -0,0 +1,30 @@
1
+ require File.expand_path("../request", __FILE__)
2
+ require File.expand_path("../config", __FILE__)
3
+ require File.expand_path("../oauth", __FILE__)
4
+
5
+ module Elmas
6
+ # @private
7
+ class API
8
+ # @private
9
+ attr_accessor *(Config::VALID_OPTIONS_KEYS)
10
+
11
+ # Creates a new API
12
+ def initialize(options = {})
13
+ options = Elmas.options.merge(options)
14
+ Config::VALID_OPTIONS_KEYS.each do |key|
15
+ send("#{key}=", options[key])
16
+ end
17
+ end
18
+
19
+ def config
20
+ conf = {}
21
+ Config::VALID_OPTIONS_KEYS.each do |key|
22
+ conf[key] = send key
23
+ end
24
+ conf
25
+ end
26
+
27
+ include Request
28
+ include OAuth
29
+ end
30
+ end
@@ -0,0 +1,11 @@
1
+ require "faraday"
2
+
3
+ module Elmas
4
+ class Client < API
5
+ def connection
6
+ Faraday.new do |faraday|
7
+ faraday.adapter Faraday.default_adapter
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,96 @@
1
+ require "faraday"
2
+
3
+ module Elmas
4
+ module Config
5
+ # An array of valid keys in the options hash
6
+ VALID_OPTIONS_KEYS = [
7
+ :access_token,
8
+ :adapter,
9
+ :client_id,
10
+ :client_secret,
11
+ :connection_options,
12
+ :redirect_uri,
13
+ :response_format,
14
+ :user_agent,
15
+ :endpoint,
16
+ :division,
17
+ :base_url,
18
+ :refresh_token
19
+ ].freeze
20
+
21
+ # By default, don't set a user access token
22
+ DEFAULT_ACCESS_TOKEN = ""
23
+
24
+ DEFAULT_REFRESH_TOKEN = ""
25
+
26
+ # The adapter that will be used to connect if none is set
27
+ #
28
+ # @note The default faraday adapter is Net::HTTP.
29
+ DEFAULT_ADAPTER = Faraday.default_adapter
30
+
31
+ # By default, client id should be set in .env
32
+ DEFAULT_CLIENT_ID = ""
33
+
34
+ # By default, client secret should be set in .env
35
+ DEFAULT_CLIENT_SECRET = ""
36
+
37
+ # By default, don't set any connection options
38
+ DEFAULT_CONNECTION_OPTIONS = {}
39
+
40
+ DEFAULT_BASE_URL = "https://start.exactonline.nl"
41
+
42
+ # The endpoint that will be used to connect if none is set
43
+ DEFAULT_ENDPOINT = "api/v1".freeze
44
+
45
+ # the division code you want to connect with
46
+ DEFAULT_DIVISION = "797636"
47
+
48
+ # The response format appended to the path and sent in the 'Accept' header if none is set
49
+ #
50
+ DEFAULT_FORMAT = :json
51
+
52
+ DEFAULT_REDIRECT_URI = "https://www.getpostman.com/oauth2/callback"
53
+
54
+ # By default, don't set user agent
55
+ DEFAULT_USER_AGENT = nil
56
+
57
+ # An array of valid request/response formats
58
+ VALID_FORMATS = [:json].freeze
59
+
60
+ # @private
61
+ attr_accessor *(VALID_OPTIONS_KEYS)
62
+
63
+ # When this module is extended, set all configuration options to their default values
64
+ def self.extended(base)
65
+ base.reset
66
+ end
67
+
68
+ # Convenience method to allow configuration options to be set in a block
69
+ def configure
70
+ yield self
71
+ end
72
+
73
+ # Create a hash of options and their values
74
+ def options
75
+ VALID_OPTIONS_KEYS.inject({}) do |option, key|
76
+ option.merge!(key => send(key))
77
+ end
78
+ end
79
+
80
+ # Reset all configuration options to defaults
81
+ def reset
82
+ self.access_token = DEFAULT_ACCESS_TOKEN
83
+ self.adapter = DEFAULT_ADAPTER
84
+ self.client_id = DEFAULT_CLIENT_ID
85
+ self.client_secret = DEFAULT_CLIENT_SECRET
86
+ self.connection_options = DEFAULT_CONNECTION_OPTIONS
87
+ self.redirect_uri = DEFAULT_REDIRECT_URI
88
+ self.endpoint = DEFAULT_ENDPOINT
89
+ self.division = DEFAULT_DIVISION
90
+ self.base_url = DEFAULT_BASE_URL
91
+ self.response_format = DEFAULT_FORMAT
92
+ self.user_agent = DEFAULT_USER_AGENT
93
+ self.refresh_token = DEFAULT_REFRESH_TOKEN
94
+ end
95
+ end
96
+ end