dech 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e75dc0ac05d00fe019e35c471e4d8bf99d987499
4
- data.tar.gz: c373618bf25961474e9812a1c204ffa74dc34419
3
+ metadata.gz: 558691d6d3a193e1034f53c757653d8b445e0ce1
4
+ data.tar.gz: 7eff60d509fe99172ec652dec658b41af0b60541
5
5
  SHA512:
6
- metadata.gz: a19d46d53d061d34999c4f2506a797ade35cc7f148fbf0dc36d7ec3830460017db6013128a788eac0c89456cf6272a4c371d65ade4f5fbab0bd3cf43bd9c24a5
7
- data.tar.gz: bd39eb4c5f5775afc549ee875a696b2761e335e8be352997a4b6be2cd6645561d792fad4ae56a7cd1147a0122e94378c64ebf1e64af12ca7fb4e4c6cee367d0e
6
+ metadata.gz: 1532a2a6c9daa0005fc6b937304b8bf4e450da8117e144f3064d0592fbe0bca1344fc98e1a18c2b23197c0b71469d235936142a224ca5d8226f241c53e064ffc
7
+ data.tar.gz: dfbc97fc9eb0673f8f770abc13217a98695a31fda768a23d26b77edb5c457819f99de71bf40b84eee48eccccfc831882545ad3e44e26530d3def468980692438
data/.rspec CHANGED
@@ -1 +1 @@
1
- --color
1
+ --color --format doc
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["OSA Shunsuke"]
10
10
  spec.email = ["hhelibebcnofnenamg@gmail.com"]
11
11
  spec.summary = %q{Utilities gem for e-commerce mall in Japan.}
12
- spec.description = %q{Dech enables you to upload price change easily.}
12
+ spec.description = %q{Dech enables to upload product information easily.}
13
13
  spec.homepage = "https://github.com/e-maido/dech"
14
14
  spec.license = "MIT"
15
15
 
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "double-bag-ftps"
22
+ spec.add_dependency "emmental"
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.5"
24
25
  spec.add_development_dependency "rake"
@@ -1,8 +1,13 @@
1
1
  # coding: utf-8
2
2
 
3
+ require "dech/hash_key_mapper"
3
4
  require "dech/version"
4
- require "dech/csvio"
5
+
6
+ require "dech/rakuten"
7
+
8
+ # deprecated classes
5
9
  require "dech/price_uploader"
10
+ require "dech/csvio"
6
11
 
7
12
  module Dech
8
13
  end
@@ -0,0 +1,41 @@
1
+ # coding: utf-8
2
+
3
+ require 'csv'
4
+ require 'stringio'
5
+
6
+ module Dech
7
+ class CSV < StringIO
8
+ DEFAULT_ENCODING = Encoding::Windows_31J
9
+
10
+ def initialize(array, args={})
11
+ @array = array
12
+ @option = {}
13
+ @option[:headers] = args[:headers] != false
14
+ @option[:encoding] = args[:encoding] || DEFAULT_ENCODING
15
+ super(csv_string)
16
+ end
17
+
18
+ def headers
19
+ @option[:headers] ? @array.first : nil
20
+ end
21
+
22
+ def save_as(path)
23
+ FileUtils.mkdir_p(File.dirname(path))
24
+ File.open(path, [:w, @option[:encoding].name].join(":")){|file| file << csv_string }
25
+ end
26
+
27
+ def to_a
28
+ @array
29
+ end
30
+
31
+ def to_s
32
+ csv_string
33
+ end
34
+
35
+ private
36
+
37
+ def csv_string
38
+ ::CSV.generate{|csv| @array.each{|row| csv << row } }.encode(@option[:encoding])
39
+ end
40
+ end
41
+ end
@@ -7,7 +7,7 @@ module Dech
7
7
  class CSVIO < StringIO
8
8
  class << self
9
9
  def generate(args={})
10
- csv_string = CSV.generate{|csv| yield(csv) if block_given? }
10
+ csv_string = ::CSV.generate{|csv| yield(csv) if block_given? }
11
11
  self.new(csv_string.encode(args[:encoding] || Encoding::Windows_31J))
12
12
  end
13
13
  end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+
3
+ module Dech
4
+ class HashKeyMapper
5
+ class << self
6
+ def map(hash, mapping)
7
+ new(hash, mapping).map
8
+ end
9
+ end
10
+
11
+ def initialize(hash={}, mapping={})
12
+ @hash = hash
13
+ @mapping = mapping
14
+ end
15
+
16
+ def map
17
+ new_hash = {}
18
+ @hash.each do |k, v|
19
+ [@mapping[k] || k].flatten.each do |new_key|
20
+ new_hash[new_key] = v
21
+ end
22
+ end
23
+ new_hash
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ # coding: utf-8
2
+ require 'dech/rakuten/ftp'
3
+
4
+ module Dech
5
+ class Rakuten
6
+ end
7
+ end
@@ -0,0 +1,57 @@
1
+ # coding: utf-8
2
+ require 'emmental'
3
+ require 'dech/csv'
4
+ require 'dech/hash_key_mapper'
5
+
6
+ module Dech
7
+ class Rakuten
8
+ class CSV < Dech::CSV
9
+ ENCODING = Encoding::Windows_31J
10
+
11
+ HEADER_MAPPINGS = {
12
+ id: "商品管理番号(商品URL)",
13
+ price: "販売価格"
14
+ }
15
+
16
+ REQUIRED_HEADERS = [
17
+ "コントロールカラム",
18
+ "商品管理番号(商品URL)"
19
+ ]
20
+
21
+ STATIC_COLUMNS = {"コントロールカラム" => "u"}
22
+
23
+ def initialize(products)
24
+ @products = products
25
+ super(formatted_products)
26
+ end
27
+
28
+ def valid?
29
+ validate! rescue false
30
+ end
31
+
32
+ def validate!
33
+ translated_products.each do |product|
34
+ REQUIRED_HEADERS.each do |header|
35
+ raise "#{header} is missing in #{product}" unless product.keys.include?(header)
36
+ end
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def formatted_products
43
+ emmental = Emmental.new
44
+ translated_products.each{|product| emmental << product }
45
+ emmental.to_a
46
+ end
47
+
48
+ def translated_products
49
+ merged_products.map{|product| Dech::HashKeyMapper.map(product, HEADER_MAPPINGS) }
50
+ end
51
+
52
+ def merged_products
53
+ @products.map{|product| STATIC_COLUMNS.merge(product) }
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,45 @@
1
+ # coding: utf-8
2
+ require 'net/ftp'
3
+ require 'dech/rakuten/csv'
4
+
5
+ module Dech
6
+ class Rakuten
7
+ class FTP
8
+ DEFAULT_HOST = "upload.rakuten.ne.jp"
9
+ DEFAULT_PATH = "/ritem/batch/item.csv"
10
+
11
+ attr_accessor :products, :username, :host, :path
12
+
13
+ def initialize(args={})
14
+ @products = args[:products] || []
15
+ @username = args[:username]
16
+ @password = args[:password]
17
+ @host = args[:host] || DEFAULT_HOST
18
+ @path = args[:path] || DEFAULT_PATH
19
+ end
20
+
21
+ def csv
22
+ Dech::Rakuten::CSV.new(@products)
23
+ end
24
+
25
+ def ready?
26
+ ftp_connection{|ftp| !ftp.nlst(File.dirname(@path)).include?(@path) }
27
+ end
28
+
29
+ def upload!
30
+ ftp_connection{|ftp| ftp.storlines("STOR #{@path}", csv) }
31
+ true
32
+ end
33
+
34
+ def upload
35
+ ready? && upload!
36
+ end
37
+
38
+ private
39
+
40
+ def ftp_connection
41
+ Net::FTP.open(@host, @username, @password){|ftp| yield(ftp) }
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
2
 
3
3
  module Dech
4
- VERSION = "0.0.3"
4
+ VERSION = "0.0.4"
5
5
  end
@@ -0,0 +1,94 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Dech::CSV do
5
+ describe "initialize" do
6
+ describe "class" do
7
+ subject{ Dech::CSV.new([]) }
8
+ it { is_expected.to be_a(StringIO) }
9
+ it { is_expected.to be_an_instance_of(Dech::CSV) }
10
+ end
11
+
12
+ describe "options" do
13
+ describe "encoding" do
14
+ context :default do
15
+ subject{ Dech::CSV.new([]).external_encoding }
16
+ it { is_expected.to be(Encoding::Windows_31J) }
17
+ end
18
+
19
+ context :given, Encoding::UTF_8 do
20
+ subject{ Dech::CSV.new([], encoding: Encoding::UTF_8).external_encoding }
21
+ it { is_expected.to be(Encoding::UTF_8) }
22
+ end
23
+ end
24
+
25
+ describe "headers" do
26
+ array = [[:col1, :col2, :col3], [1, 2, 3]]
27
+
28
+ context "default with", array.first do
29
+ subject{ Dech::CSV.new(array).headers }
30
+ it { is_expected.to eq(array.first) }
31
+ end
32
+
33
+ context "given false with", array.first do
34
+ subject{ Dech::CSV.new(array, headers: false).headers }
35
+ it { is_expected.to eq(nil) }
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "#to_a" do
42
+ array = [[:col1, :col2, :col3], [1, 2, 3]]
43
+ subject{ Dech::CSV.new(array).to_a }
44
+
45
+ it { is_expected.to be_an_instance_of(Array) }
46
+
47
+ context :given, array do
48
+ it { is_expected.to eq(array) }
49
+ end
50
+ end
51
+
52
+ describe "#to_s" do
53
+ array = [[:col1, :col2, :col3], [1, 2, 3]]
54
+ subject{ Dech::CSV.new(array).to_s }
55
+
56
+ it { is_expected.to be_an_instance_of(String) }
57
+
58
+ context :given, array do
59
+ array.each do |row|
60
+ row.each do |cell|
61
+ it { is_expected.to include(cell.to_s) }
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ describe "#save_as(path)" do
68
+ let(:dirname) { "tmp" }
69
+ let(:filename){ "#{Time.now.strftime("%Y%m%d_%H%M%S_%N")}.csv" }
70
+ let(:path) { File.join(dirname, filename) }
71
+ subject{ lambda{ Dech::CSV.new([]).save_as(path) } }
72
+
73
+ it { is_expected.to change{Dir.glob(File.join(dirname, "*")).size}.by(1) }
74
+
75
+ describe "saved file" do
76
+ before { subject.call }
77
+
78
+ it "should exist" do
79
+ expect(Dir.glob(File.join(dirname, "*"))).to include(path)
80
+ end
81
+
82
+ it "should be valid CSV" do
83
+ CSV.open(path, "r:windows-31j:utf-8", headers: true) do |csv|
84
+ expect{csv.readlines}.not_to raise_error
85
+ end
86
+ end
87
+ end
88
+
89
+ after do
90
+ files = Dir.glob(File.join(dirname, "*"))
91
+ FileUtils.remove(files)
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,46 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Dech::HashKeyMapper do
5
+ describe "class methods" do
6
+ describe ".map" do
7
+ it "should call #{described_class}#map" do
8
+ hash = {}
9
+ mapping = {}
10
+
11
+ mapper = double("mapper")
12
+ expect(mapper).to receive(:map)
13
+ expect(described_class).to receive(:new).with(hash, mapping).and_return(mapper)
14
+
15
+ described_class.map(hash, mapping)
16
+ end
17
+ end
18
+ end
19
+
20
+ describe "initialize" do
21
+ subject{ described_class.new }
22
+ it { is_expected.to be_an_instance_of(described_class) }
23
+ end
24
+
25
+ describe "#map" do
26
+ context "1 key to 1 key" do
27
+ hash = {foo: "foo", bar: "bar", fizz: "fizz"}
28
+ mapping = {foo: "FOO", fizz: "FIZZ"}
29
+
30
+ subject{ described_class.new(hash, mapping).map }
31
+ it "should rename a key" do
32
+ is_expected.to eq({"FOO" => "foo", bar: "bar", "FIZZ" => "fizz"})
33
+ end
34
+ end
35
+
36
+ context "1 key to n keys" do
37
+ hash = {foo: "foo", bar: "bar", fizz: "fizz"}
38
+ mapping = {foo: ["FOO", "Foo"], fizz: "FIZZ"}
39
+
40
+ subject{ described_class.new(hash, mapping).map }
41
+ it "should remove a old key and add new keys" do
42
+ is_expected.to eq({"FOO" => "foo", "Foo" => "foo", bar: "bar", "FIZZ" => "fizz"})
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,62 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Dech::Rakuten::CSV do
5
+ describe "initialize" do
6
+ products = [
7
+ {id: "ABC-001", price: 12800},
8
+ {id: "xyz-123", price: 9800}
9
+ ]
10
+
11
+ subject{ Dech::Rakuten::CSV.new(products) }
12
+ it { is_expected.to be_an_instance_of(Dech::Rakuten::CSV) }
13
+ it { is_expected.to be_a(Dech::CSV) }
14
+ it { is_expected.to be_a(StringIO) }
15
+
16
+ p Dech::Rakuten::CSV.new(products).to_a
17
+ end
18
+
19
+ describe "#valid?" do
20
+ context "with valid columns" do
21
+ products = [
22
+ {id: "ABC-001", price: 12800},
23
+ {id: "xyz-123", price: 9800}
24
+ ]
25
+
26
+ subject{ Dech::Rakuten::CSV.new(products) }
27
+ it { is_expected.to be_valid }
28
+ end
29
+
30
+ context "with invalid columns" do
31
+ products = [
32
+ {price: 12800},
33
+ {price: 9800}
34
+ ]
35
+
36
+ subject{ Dech::Rakuten::CSV.new(products) }
37
+ it { is_expected.not_to be_valid }
38
+ end
39
+ end
40
+
41
+ describe "#validate!" do
42
+ context "valid columns" do
43
+ products = [
44
+ {id: "ABC-001", price: 12800},
45
+ {id: "xyz-123", price: 9800}
46
+ ]
47
+
48
+ subject{ lambda{ Dech::Rakuten::CSV.new(products).validate! } }
49
+ it { is_expected.not_to raise_error }
50
+ end
51
+
52
+ context "invalid columns" do
53
+ products = [
54
+ {price: 12800},
55
+ {price: 9800}
56
+ ]
57
+
58
+ subject{ lambda{ Dech::Rakuten::CSV.new(products).validate! } }
59
+ it { is_expected.to raise_error }
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,93 @@
1
+ # coding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Dech::Rakuten::FTP do
6
+ let(:ftp) {
7
+ described_class.new(
8
+ products: [{id: "PRODUCT-CODE", price: 9800}],
9
+ username: "username",
10
+ password: "password",
11
+ host: "example.com"
12
+ )
13
+ }
14
+
15
+ let(:net_ftp) {
16
+ net_ftp = double("net_ftp")
17
+ allow(net_ftp).to receive(:passive=)
18
+ allow(net_ftp).to receive(:connect)
19
+ allow(net_ftp).to receive(:login)
20
+ allow(net_ftp).to receive(:close)
21
+ expect(Net::FTP).to receive(:new).and_return(net_ftp)
22
+ net_ftp
23
+ }
24
+
25
+ describe "initialize" do
26
+ subject { ftp }
27
+ it { is_expected.to be_an_instance_of(described_class) }
28
+ end
29
+
30
+ describe "#csv" do
31
+ subject { ftp.csv }
32
+ it { is_expected.to be_an_instance_of(Dech::Rakuten::CSV) }
33
+ end
34
+
35
+ describe "#ready?" do
36
+ subject { ftp.ready? }
37
+
38
+ context "CSV file exists in FTP server" do
39
+ before { expect(net_ftp).to receive(:nlst).and_return([ftp.path]) }
40
+ it { is_expected.to be false }
41
+ end
42
+
43
+ context "CSV file does not exist in FTP server" do
44
+ before { expect(net_ftp).to receive(:nlst).and_return([]) }
45
+ it { is_expected.to be true }
46
+ end
47
+ end
48
+
49
+ describe "#upload!" do
50
+ subject{ lambda{ ftp.upload! } }
51
+
52
+ it "should upload CSV file to the path on FTP server" do
53
+ expect(net_ftp).to receive(:storlines)
54
+ subject.call
55
+ end
56
+ end
57
+
58
+ =begin
59
+ describe "#upload" do
60
+ context "server is ready" do
61
+ before do
62
+ allow(ftp).to receive(:nlst).and_return([])
63
+ expect(ftp).to receive(:storlines)
64
+ expect(Net::FTP).to receive(:new).and_return(ftp).at_least(:once)
65
+ end
66
+
67
+ it "should upload CSV file to the path on FTP server" do
68
+ expect(dech.upload).to be true
69
+ end
70
+ end
71
+ end
72
+ =end
73
+
74
+ describe "#upload" do
75
+ subject{ lambda{ ftp.upload } }
76
+
77
+ context "FTP server is ready" do
78
+ it "should call #upload!" do
79
+ expect(ftp).to receive(:ready?).and_return(true)
80
+ expect(ftp).to receive(:upload!).and_return(true)
81
+ subject.call
82
+ end
83
+ end
84
+
85
+ context "FTP server is not ready" do
86
+ it "should not call #upload!" do
87
+ expect(ftp).to receive(:ready?).and_return(false)
88
+ expect(ftp).not_to receive(:upload!)
89
+ subject.call
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,5 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Dech::Rakuten do
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dech
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - OSA Shunsuke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-21 00:00:00.000000000 Z
11
+ date: 2014-08-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: double-bag-ftps
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: emmental
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,7 +94,7 @@ dependencies:
80
94
  - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
83
- description: Dech enables you to upload price change easily.
97
+ description: Dech enables to upload product information easily.
84
98
  email:
85
99
  - hhelibebcnofnenamg@gmail.com
86
100
  executables: []
@@ -97,16 +111,26 @@ files:
97
111
  - Rakefile
98
112
  - dech.gemspec
99
113
  - lib/dech.rb
114
+ - lib/dech/csv.rb
100
115
  - lib/dech/csvio.rb
116
+ - lib/dech/hash_key_mapper.rb
101
117
  - lib/dech/price_uploader.rb
102
118
  - lib/dech/price_uploader/dena.rb
103
119
  - lib/dech/price_uploader/dena/ftp.rb
104
120
  - lib/dech/price_uploader/ponpare.rb
105
121
  - lib/dech/price_uploader/ponpare/ftps.rb
122
+ - lib/dech/rakuten.rb
123
+ - lib/dech/rakuten/csv.rb
124
+ - lib/dech/rakuten/ftp.rb
106
125
  - lib/dech/version.rb
126
+ - spec/dech/csv_spec.rb
107
127
  - spec/dech/csvio_spec.rb
128
+ - spec/dech/hash_key_mapper_spec.rb
108
129
  - spec/dech/price_uploader/dena/ftp_spec.rb
109
130
  - spec/dech/price_uploader/ponpare/ftps_spec.rb
131
+ - spec/dech/rakuten/csv_spec.rb
132
+ - spec/dech/rakuten/ftp_spec.rb
133
+ - spec/dech/rakuten_spec.rb
110
134
  - spec/dech_spec.rb
111
135
  - spec/spec_helper.rb
112
136
  homepage: https://github.com/e-maido/dech
@@ -134,8 +158,13 @@ signing_key:
134
158
  specification_version: 4
135
159
  summary: Utilities gem for e-commerce mall in Japan.
136
160
  test_files:
161
+ - spec/dech/csv_spec.rb
137
162
  - spec/dech/csvio_spec.rb
163
+ - spec/dech/hash_key_mapper_spec.rb
138
164
  - spec/dech/price_uploader/dena/ftp_spec.rb
139
165
  - spec/dech/price_uploader/ponpare/ftps_spec.rb
166
+ - spec/dech/rakuten/csv_spec.rb
167
+ - spec/dech/rakuten/ftp_spec.rb
168
+ - spec/dech/rakuten_spec.rb
140
169
  - spec/dech_spec.rb
141
170
  - spec/spec_helper.rb