insales_api 0.0.13 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -0
  3. data/CHANGELOG.md +20 -0
  4. data/Gemfile +1 -1
  5. data/README.md +57 -0
  6. data/Rakefile +8 -1
  7. data/insales_api.gemspec +12 -12
  8. data/lib/insales/controller/autologin.rb +45 -0
  9. data/lib/insales/controller/base_helpers.rb +52 -0
  10. data/lib/insales/controller/installer_actions.rb +19 -0
  11. data/lib/insales/controller/session_actions.rb +39 -0
  12. data/lib/insales/controller.rb +10 -0
  13. data/lib/insales.rb +7 -0
  14. data/lib/insales_api/account.rb +1 -9
  15. data/lib/insales_api/active_resource_proxy.rb +31 -0
  16. data/lib/insales_api/app.rb +57 -38
  17. data/lib/insales_api/application_charge.rb +3 -0
  18. data/lib/insales_api/asset.rb +3 -1
  19. data/lib/insales_api/base.rb +41 -5
  20. data/lib/insales_api/category.rb +8 -2
  21. data/lib/insales_api/client.rb +3 -1
  22. data/lib/insales_api/client_group.rb +3 -0
  23. data/lib/insales_api/collect.rb +8 -2
  24. data/lib/insales_api/discount_code.rb +3 -0
  25. data/lib/insales_api/helpers/has_insales_object.rb +34 -0
  26. data/lib/insales_api/helpers/init_api.rb +98 -0
  27. data/lib/insales_api/image.rb +5 -0
  28. data/lib/insales_api/order.rb +13 -5
  29. data/lib/insales_api/order_line.rb +2 -2
  30. data/lib/insales_api/product.rb +3 -1
  31. data/lib/insales_api/product_field.rb +3 -0
  32. data/lib/insales_api/product_field_value.rb +22 -0
  33. data/lib/insales_api/property.rb +3 -0
  34. data/lib/insales_api/resource/countable.rb +9 -0
  35. data/lib/insales_api/resource/paginated.rb +26 -0
  36. data/lib/insales_api/resource/with_updated_since.rb +28 -0
  37. data/lib/insales_api/theme.rb +7 -1
  38. data/lib/insales_api/variant.rb +18 -6
  39. data/lib/insales_api/version.rb +7 -1
  40. data/lib/insales_api.rb +74 -17
  41. data/spec/lib/insales_api/active_resource_proxy_spec.rb +59 -0
  42. data/spec/lib/insales_api/app_spec.rb +67 -0
  43. data/spec/lib/insales_api_spec.rb +110 -0
  44. data/spec/spec_helper.rb +3 -4
  45. metadata +54 -20
  46. data/README +0 -32
  47. data/spec/lib/insales_app_spec.rb +0 -63
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 21c7b7e853b3998b60bd9e067abc75be2837608d
4
- data.tar.gz: 1e3cdaf7a448b016227d6fc8f5b2f4a82ae48572
3
+ metadata.gz: 0874e0c3d9d031bd7c44623652e9f8d0118bbca1
4
+ data.tar.gz: d8f445c2fd2f722d03368b0cef92430f4bb338b4
5
5
  SHA512:
6
- metadata.gz: 7f62cd468de7f1da9773068404b6b715a420d68eb106b2b3a3f15a9cd18da7cc3bc6c47d3aa4bd45cd90c751c2243687958b076b0a32fcc5b99a5c25fc4c56de
7
- data.tar.gz: ac1324ae0d02fb0995752d05987f764e05cfda89afabc1c17e7ebe5ea60e6ad0f2fef0aa3338267cb2b4a3bfcb350deb537f264427091925b6347ee3eb94a9c8
6
+ metadata.gz: 106dfba38c2704be7e63243f6493d441d440a200dc9f6a39454e21ea40c765cf16d5859f8103f5305786445ced8a42014603dbd1a43c56dc67adf8bea23bdc82
7
+ data.tar.gz: de95a094d63c5e09583943e56296f3d66f2a91e37246538afb499e7aae6252a832044acb8eaf74fa16a9c97dd163752bf5862c050af4dad5bc37ec03e1b9d5ed
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.1.0
5
+ notifications:
6
+ email: false
data/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## 0.1.0
2
+
3
+ * Helpers
4
+ * ProductFieldValue
5
+ * Controller auth mixins
6
+ * Account inherits AR::Singleton (it breaks ::current & #update methods)
7
+ * Added wait_retry method
8
+ * Added Property resource
9
+ * Added ProductField resource
10
+ * Added ClientGroup resource
11
+
12
+ ## 0.0.14
13
+
14
+ * Added Image resource
15
+ * Fixed Variant.group_update
16
+ * Added DiscountCode resource
17
+ * Added Product.count method
18
+ * Added Order.paid? method
19
+ * Added ApplicationCharge resource
20
+
1
21
  ## 0.0.13
2
22
 
3
23
  * ActiveResource::Singleton backport.
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source 'http://rubygems.org'
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # InsalesApi gem
2
+
3
+ [![Build Status](https://secure.travis-ci.org/insales/insales_api.png?branch=master)](http://travis-ci.org/insales/insales_api)
4
+
5
+ Insales api client based on [ActiveResource](https://github.com/rails/activeresource).
6
+
7
+ Rails application example is [here](https://github.com/insales/insales_app).
8
+
9
+ ## Install
10
+
11
+ Add to Gemfile:
12
+
13
+ ```ruby
14
+ gem 'insales_api'
15
+ ```
16
+
17
+ ## Initialize
18
+
19
+ ```ruby
20
+ class MyApp < InsalesApi::App
21
+ self.api_key = 'api_key'
22
+ end
23
+
24
+ MyApp.configure_api('domain', 'password')
25
+ ```
26
+
27
+ ## Use
28
+
29
+ ```ruby
30
+ order = InsalesApi::Order.find 123
31
+
32
+ # singleton resources
33
+ account = InsalesApi::Account.find
34
+ ```
35
+
36
+ ### Handling Insales API request limit
37
+
38
+ There is a 500 requests per 5 minutes limit for Insales API. To handle this limitation gracefully, use `InsalesApi.wait_retry` method:
39
+ ```ruby
40
+ # prepare a handler for request limit case
41
+ notify_user = Proc.new do |wait_for, attempt, max_attempts, ex|
42
+ puts "API limit reached. Waiting for #{wait_for} seconds. Attempt #{attempt}/#{max_attempts}"
43
+ end
44
+
45
+ # perform 10 attempts to get products
46
+ InsalesApi.wait_retry(10, notify_user) do |x|
47
+ puts "Attempt ##{x}."
48
+ products = InsalesApi::Products.all
49
+ end
50
+ ```
51
+
52
+ If you don't need to cap the attempts number or you don't want to do any special processing, simply drop the arguments:
53
+ ```ruby
54
+ InsalesApi.wait_retry do
55
+ products = InsalesApi::Products.all # will try to get products until the limit resets
56
+ end
57
+ ```
data/Rakefile CHANGED
@@ -1 +1,8 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new do |t|
5
+ t.pattern = 'spec/**/*_spec.rb'
6
+ end
7
+
8
+ task default: :spec
data/insales_api.gemspec CHANGED
@@ -1,23 +1,23 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "insales_api/version"
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+ require 'insales_api/version'
4
3
 
5
4
  Gem::Specification.new do |s|
6
- s.name = "insales_api"
7
- s.version = InsalesApi::VERSION
8
- s.authors = "InSales"
9
- s.email = "dg@insales.ru"
10
- s.homepage = "http://wiki.insales.ru/wiki/%D0%9A%D0%B0%D0%BA_%D0%B8%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%D1%81%D1%8F_%D1%81_InSales"
5
+ s.name = 'insales_api'
6
+ s.version = InsalesApi::VERSION::STRING
7
+ s.authors = 'InSales'
8
+ s.email = 'dg@insales.ru'
9
+ s.homepage = 'https://github.com/insales/insales_api'
11
10
  s.summary = %q{Gem for accessing the InSales REST web services}
12
11
  s.description = %q{Gem for accessing the InSales REST web services}
13
12
 
14
- s.rubyforge_project = "insales_api"
13
+ s.rubyforge_project = 'insales_api'
15
14
 
16
15
  s.files = `git ls-files`.split("\n")
17
16
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
18
 
20
- s.add_dependency("activesupport", [">= 3.0.0"])
21
- s.add_dependency("activeresource", [">= 3.0.0"])
22
- s.add_development_dependency "rspec"
19
+ s.add_dependency('activesupport', ['>= 3.0.0'])
20
+ s.add_dependency('activeresource', ['>= 3.0.0'])
21
+ s.add_development_dependency 'rspec', '~> 2.13.0'
22
+ s.add_development_dependency 'rake', '~> 10.3'
23
23
  end
@@ -0,0 +1,45 @@
1
+ module Insales::Controller
2
+ module Autologin
3
+ protected
4
+ def insales_authenticate!
5
+ params[:domain] ||= params[:shop]
6
+ insales_logout if params[:domain].present? && params[:domain] != session[:domain]
7
+ return if insales_authenticate_from_session
8
+ store_location
9
+ account = find_account_by_request
10
+ return insales_autologin_start(account) if account
11
+ redirect_to insales_login_path
12
+ end
13
+
14
+ def insales_authenticate_from_session
15
+ data = session[:insales_session]
16
+ return unless data && data[:account_id] && data[:insales_id]
17
+ @account = account_class.where(account_id: data[:account_id]).
18
+ find_by_insales_id(data[:insales_id])
19
+ end
20
+
21
+ def insales_autologin_start(account)
22
+ app = insales_app_class.new(account.insales_domain, account.insales_password)
23
+ auth_url = app.authorization_url
24
+ session[:insales_token] = app.auth_token
25
+ session[:insales_token_data] = {
26
+ domain: account.insales_domain,
27
+ account_id: account.id,
28
+ insales_id: account.insales_id,
29
+ }
30
+ redirect_to auth_url
31
+ end
32
+
33
+ def insales_autologin_finish(token = params[:token])
34
+ if token && session[:insales_token] == token && session[:insales_token_data].is_a?(Hash)
35
+ session[:insales_session] = session[:insales_token_data]
36
+ end
37
+ session[:insales_token] = session[:insales_token_data] = nil
38
+ session[:account_id].present?
39
+ end
40
+
41
+ def insales_logout
42
+ session.delete(:insales_session)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,52 @@
1
+ module Insales::Controller
2
+ module BaseHelpers
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ class_attribute :insales_config
7
+ self.insales_config = {
8
+ account_class: '::Account',
9
+ insales_app_class: '::InsalesApi::App',
10
+ login_path: 'login_path',
11
+ success_login_path: 'account_path',
12
+ }
13
+
14
+ def account_class
15
+ @account_class ||= insales_config[:account_class].constantize
16
+ end
17
+
18
+ def insales_app_class
19
+ @insales_app_class ||= insales_config[:insales_app_class].constantize
20
+ end
21
+
22
+ def insales_login_path
23
+ send(insales_config[:login_path])
24
+ end
25
+
26
+ def insales_success_login_path
27
+ send(insales_config[:success_login_path])
28
+ end
29
+ end
30
+
31
+ protected
32
+ delegate :insales_app_class, :account_class,
33
+ :insales_login_path, :insales_success_login_path,
34
+ to: :class
35
+
36
+ def store_location(path = request.url)
37
+ session[:return_to] = path
38
+ end
39
+
40
+ def stored_location
41
+ session.delete(:return_to)
42
+ end
43
+
44
+ def find_account_by_request
45
+ if params[:insales_id]
46
+ account_class.find_by_insales_id(params[:insales_id])
47
+ elsif params[:domain]
48
+ account_class.find_by_insales_domain(params[:domain])
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,19 @@
1
+ module Insales::Controller
2
+ module InstallerActions
3
+ def install
4
+ if insales_app_class.install(params[:shop], params[:token], params[:insales_id])
5
+ head :ok
6
+ else
7
+ raise 'Instalation failed'
8
+ end
9
+ end
10
+
11
+ def uninstall
12
+ if insales_app_class.uninstall(params[:shop], params[:token])
13
+ head :ok
14
+ else
15
+ raise 'Uninstallation failed'
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,39 @@
1
+ module Insales::Controller
2
+ module SessionActions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ skip_before_filter :insales_authenticate!, except: [:destroy]
7
+ end
8
+
9
+ def new
10
+ # render
11
+ end
12
+
13
+ def create
14
+ account = find_account_by_request
15
+ return render_not_found unless account
16
+ store_location(insales_success_login_path)
17
+ insales_autologin_start(account)
18
+ end
19
+
20
+ def autologin
21
+ if insales_autologin_finish
22
+ redirect_to stored_location || insales_success_login_path
23
+ else
24
+ redirect_to action: :new
25
+ end
26
+ end
27
+
28
+ def destroy
29
+ insales_logout
30
+ redirect_to action: :new
31
+ end
32
+
33
+ protected
34
+ def render_not_found
35
+ flash.now[:error] = t(:'.account_not_found').html_safe
36
+ render action: :new
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,10 @@
1
+ module Insales
2
+ module Controller
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :BaseHelpers
6
+ autoload :Autologin
7
+ autoload :SessionActions
8
+ autoload :InstallerActions
9
+ end
10
+ end
data/lib/insales.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'insales_api'
2
+
3
+ module Insales
4
+ extend ActiveSupport::Autoload
5
+
6
+ autoload :Controller
7
+ end
@@ -1,13 +1,5 @@
1
1
  module InsalesApi
2
2
  class Account < Base
3
- def self.current
4
- find(:one, :from => '/admin/account.xml')
5
- end
6
-
7
- def update
8
- connection.put('/admin/account.xml', encode, self.class.headers).tap do |response|
9
- load_attributes_from_response(response)
10
- end
11
- end
3
+ include ActiveResource::Singleton
12
4
  end
13
5
  end
@@ -0,0 +1,31 @@
1
+ module InsalesApi
2
+ class ActiveResourceProxy
3
+ class << self
4
+ def need_proxy?(value)
5
+ return true if value.is_a?(Hash) || value.is_a?(Array)
6
+ klass = value.is_a?(Class) ? value : value.class
7
+ return true if klass < Base || klass <= ActiveResource::Collection
8
+ false
9
+ end
10
+ end
11
+
12
+ def initialize(configurer, subject)
13
+ @configurer = configurer
14
+ @subject = subject
15
+ end
16
+
17
+ def respond_to_missing?(method_name)
18
+ @subject.respond_to?(method_name) || super
19
+ end
20
+
21
+ def method_missing(method_id, *args, &block)
22
+ @configurer.init_api { proxy_for @subject.send(method_id, *args, &block) }
23
+ end
24
+
25
+ private
26
+ def proxy_for(value)
27
+ return value unless self.class.need_proxy?(value)
28
+ self.class.new(@configurer, value)
29
+ end
30
+ end
31
+ end
@@ -1,35 +1,72 @@
1
1
  module InsalesApi
2
2
  class App
3
- class_attribute :api_key, :api_host, :api_secret, :api_autologin_path
4
- attr_reader :authorized, :auth_token, :shop, :password
3
+ class_attribute :api_key, :api_secret, :api_autologin_url, :api_host, :api_autologin_path,
4
+ :base_resource_class
5
+ attr_reader :authorized, :domain, :password
6
+ self.base_resource_class = Base
5
7
 
6
- def initialize(shop, password)
8
+ class << self
9
+ def configure_api(domain, password)
10
+ base_resource_class.configure(api_key, domain, password)
11
+ end
12
+
13
+ delegate :dump_config, :restore_config, to: :base_resource_class
14
+
15
+ def prepare_domain(domain)
16
+ domain.to_s.strip.downcase
17
+ end
18
+
19
+ alias_method :prepare_shop, :prepare_domain
20
+ deprecate prepare_shop: :prepare_domain,
21
+ api_host: :api_autologin_url,
22
+ api_autologin_path: :api_autologin_url,
23
+ deprecator: Deprecator
24
+
25
+ def install(domain, token, insales_id)
26
+ true
27
+ end
28
+
29
+ def uninstall(domain, password)
30
+ true
31
+ end
32
+
33
+ def password_by_token(token)
34
+ InsalesApi::Password.create(api_secret, token)
35
+ end
36
+ end
37
+
38
+ def initialize(domain, password)
7
39
  @authorized = false
8
- @shop = self.class.prepare_shop shop
40
+ @domain = self.class.prepare_domain(domain)
9
41
  @password = password
10
42
  end
11
43
 
12
44
  def authorization_url
13
- store_auth_token
14
- "http://#{shop}/admin/applications/#{self.class.api_key}/login?" \
15
- "token=#{salt}&login=http://#{self.class.api_host}/#{self.class.api_autologin_path}"
45
+ host, port = domain, nil
46
+ match = /(.+):(\d+)/.match host
47
+ host, port = match[1..2] if match
48
+ URI::Generic.build(
49
+ scheme: 'http',
50
+ host: host,
51
+ port: port && port.to_i,
52
+ path: "/admin/applications/#{api_key}/login",
53
+ query: {
54
+ token: salt,
55
+ login: api_autologin_url || "http://#{api_host}/#{api_autologin_path}",
56
+ }.to_query,
57
+ ).to_s
16
58
  end
17
59
 
18
- def store_auth_token
60
+ def auth_token
19
61
  @auth_token ||= InsalesApi::Password.create(password, salt)
20
62
  end
21
63
 
22
64
  def salt
23
- @salt ||= Digest::MD5.hexdigest("Twulvyeik#{$$}#{Time.now.to_i}thithAwn")
65
+ @salt ||= SecureRandom.hex
24
66
  end
25
67
 
26
- def authorize token
27
- @authorized = false
28
- if self.auth_token and self.auth_token == token
29
- @authorized = true
30
- end
31
-
32
- @authorized
68
+ def authorize(token)
69
+ @authorized = auth_token == token
33
70
  end
34
71
 
35
72
  def authorized?
@@ -37,29 +74,11 @@ module InsalesApi
37
74
  end
38
75
 
39
76
  def configure_api
40
- self.class.configure_api shop, password
77
+ self.class.configure_api(domain, password)
41
78
  end
42
79
 
43
- class << self
44
- def configure_api shop, password
45
- InsalesApi::Base.configure api_key, shop, password
46
- end
47
-
48
- def prepare_shop shop
49
- shop.to_s.strip.downcase
50
- end
51
-
52
- def install shop, token, insales_id
53
- true
54
- end
55
-
56
- def uninstall shop, password
57
- true
58
- end
59
-
60
- def password_by_token token
61
- InsalesApi::Password.create(api_secret, token)
62
- end
63
- end
80
+ alias_method :store_auth_token, :auth_token
81
+ alias_method :shop, :domain
82
+ deprecate store_auth_token: :auth_token, shop: :domain, deprecator: Deprecator
64
83
  end
65
84
  end
@@ -0,0 +1,3 @@
1
+ module InsalesApi
2
+ class ApplicationCharge < Base; end
3
+ end
@@ -1,3 +1,5 @@
1
1
  module InsalesApi
2
- class Asset < Base; end
2
+ class Asset < Base
3
+ self.prefix = "#{prefix}themes/:theme_id/"
4
+ end
3
5
  end
@@ -1,12 +1,48 @@
1
+ require 'insales_api/resource/countable'
2
+ require 'insales_api/resource/paginated'
3
+ require 'insales_api/resource/with_updated_since'
4
+ require 'insales_api/active_resource_proxy'
5
+
1
6
  module InsalesApi
2
7
  class Base < ActiveResource::Base
8
+ extend Resource::Countable
9
+ extend Resource::Paginated
10
+
11
+ self.include_root_in_json = false
12
+ self.headers['User-Agent'] = %W(
13
+ InsalesApi/#{InsalesApi::VERSION}
14
+ ActiveResource/#{ActiveResource::VERSION::STRING}
15
+ Ruby/#{RUBY_VERSION}
16
+ ).join(' ')
3
17
  self.format = :xml
18
+ self.prefix = '/admin/'
19
+
20
+ class << self
21
+ def configure(api_key, domain, password)
22
+ self.user = api_key
23
+ self.site = "http://#{domain}"
24
+ self.password = password
25
+ self
26
+ end
27
+
28
+ def dump_config
29
+ {
30
+ user: self.user,
31
+ site: self.site,
32
+ password: self.password,
33
+ }
34
+ end
35
+
36
+ def restore_config(options)
37
+ self.user = options[:user]
38
+ self.site = options[:site]
39
+ self.password = options[:password]
40
+ true
41
+ end
4
42
 
5
- def self.configure(api_key, shop, password)
6
- self.user = api_key
7
- self.site = "http://#{shop}/admin/"
8
- self.password = password
9
- nil
43
+ def for_account(account)
44
+ ActiveResourceProxy.new(account, self)
45
+ end
10
46
  end
11
47
  end
12
48
  end
@@ -1,7 +1,13 @@
1
1
  module InsalesApi
2
2
  class Category < Base
3
- def self.set_products_category new_category_id, product_ids
4
- connection.put("/admin/categories/set_products_category.xml", {:id => new_category_id, :product_ids => Array(product_ids)}.to_xml(:root => :new_category), headers)
3
+ class << self
4
+ def set_products_category(new_category_id, product_ids)
5
+ data = {
6
+ id: new_category_id,
7
+ product_ids: Array(product_ids),
8
+ }
9
+ put(:set_products_category, {}, format.encode(data, root: :new_category))
10
+ end
5
11
  end
6
12
  end
7
13
  end
@@ -1,3 +1,5 @@
1
1
  module InsalesApi
2
- class Client < Base; end
2
+ class Client < Base
3
+ extend Resource::WithUpdatedSince
4
+ end
3
5
  end
@@ -0,0 +1,3 @@
1
+ module InsalesApi
2
+ class ClientGroup < Base; end
3
+ end
@@ -1,7 +1,13 @@
1
1
  module InsalesApi
2
2
  class Collect < Base
3
- def self.group_create product_ids, collection_ids
4
- connection.post("/admin/collects/group_create.xml", {:collection_ids => Array(collection_ids), :product_ids => Array(product_ids)}.to_xml(:root => :group_create), headers)
3
+ class << self
4
+ def group_create(product_ids, collection_ids)
5
+ data = {
6
+ collection_ids: Array(collection_ids),
7
+ product_ids: Array(product_ids),
8
+ }
9
+ post(:group_create, {}, format.encode(data, root: :group_create))
10
+ end
5
11
  end
6
12
  end
7
13
  end
@@ -0,0 +1,3 @@
1
+ module InsalesApi
2
+ class DiscountCode < Base; end
3
+ end
@@ -0,0 +1,34 @@
1
+ module InsalesApi::Helpers
2
+ module HasInsalesObject
3
+ def has_insales_object(type, options = {})
4
+ i_method_name = "insales_#{type}"
5
+ class_method_name = "insales_#{type}_class"
6
+ object_class = options[:class] || InsalesApi.const_get(type.to_s.camelcase)
7
+ helpers = Module.new do
8
+ extend ActiveSupport::Concern
9
+
10
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
11
+ included do # included do
12
+ class_attribute :#{class_method_name} # class_attribute :insales_order_class
13
+ self.#{class_method_name} = #{object_class} # self.insales_order_class = InsalesApi::Order
14
+ end # end
15
+ #
16
+ def #{i_method_name}(force = false) # def insales_order(force = false)
17
+ return @#{i_method_name} if @#{i_method_name} && !force # return @insales_order if @insales_order && !force
18
+ @#{i_method_name} = init_api do # @insales_order = init_api do
19
+ #{class_method_name}.find(insales_id) # insales_order_class.find(insales_id)
20
+ end # end
21
+ end # end
22
+ #
23
+ attr_writer :#{i_method_name} # attr_writer :insales_order
24
+ #
25
+ def reload(*) # def reload(*)
26
+ @#{i_method_name} = nil # @insales_order = nil
27
+ super # super
28
+ end # end
29
+ RUBY
30
+ end
31
+ include helpers
32
+ end
33
+ end
34
+ end