Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

रूबी डिपेंडेंसी मैनेजमेंट में महारत हासिल करना: Rbenv, RubyGems, और Bundler कैसे इंटरैक्ट करते हैं

रूबी में निर्भरताओं को प्रबंधित करना आमतौर पर उन रूबी और जेम संस्करणों को निर्दिष्ट करने पर निर्भर करता है जिन पर हमारा प्रोजेक्ट निर्भर करता है। रूबी के साथ काम करने के अपने अनुभव में, डिपेंडेंसीज़ को डीबग करना मेरी सबसे बड़ी चुनौतियों में से एक रहा है। विफलताएं आम नहीं हैं क्योंकि कई चीजें "बस काम करती हैं"; हालांकि, जब चीजें गलत होती हैं, तो वे आमतौर पर अनावश्यक रूप से डीबग और ठीक करने में कठिन होती हैं। इस लेख में, मैं रूबी में डिपेंडेंसी मैनेजमेंट में शामिल टुकड़ों को रखूंगा। यह उन अजीब मुद्दों को डीबग करने में सहायता करेगा जब वे होते हैं।

रूबी डिपेंडेंसी मैनेजमेंट में महारत हासिल करना: Rbenv, RubyGems, और Bundler कैसे इंटरैक्ट करते हैं

रूबी कोड लोडिंग

डिफ़ॉल्ट रूप से, रूबी भाषा अन्यत्र परिभाषित कोड को लोड करने के लिए दो प्रमुख मेथड्स प्रदान करती है: load और require।

load 'json.rb' require 'json.rb' require_relative 'json.rb' 

दोनों लोडिंग मेथड्स आर्गुमेंट्स के रूप में पूर्ण और सापेक्ष दोनों पथ स्वीकार करते हैं। हालांकि, दो अलग करने वाले कारक हैं:

  1. load के कई कॉल फाइल को फिर से निष्पादित करेंगे, जबकि require के कई कॉल फाइल को फिर से निष्पादित नहीं करेंगे; इसके बजाय, यह false लौटाएगा।
  2. load के कॉल केवल पूर्ण और सापेक्ष पथों पर हल होते हैं। require के कॉल $LOAD_PATH पर जांच करते हैं जब पथ पूर्ण पथ पर हल नहीं होता।

एक तीसरा संस्करण require_relative है, जो वर्तमान फाइल के स्थान के सापेक्ष कोड को आवश्यक करने के लिए सापेक्ष पथों का उपयोग करता है न कि रूबी प्रोसेस की वर्किंग डायरेक्टरी के।

Rbenv

एक वर्जन मैनेजर हमारे इंटरप्रेटर (इस मामले में, रूबी) के संस्करणों को प्रबंधित और आसानी से स्विच करने और हमारे प्रोजेक्ट के लिए संबंधित जेम्स को खोजने के लिए स्थान निर्दिष्ट करने के लिए उपयोग किया जाने वाला टूल है। वर्जन मैनेजर्स काफी हद तक भाषा-अज्ञेयवादी टूल्स हैं, और विभिन्न भाषाओं के अपने संबंधित कार्यान्वयन हैं, जैसे Nvm, n Node.js के लिए, pyenv Python के लिए, और Rbenv, rvm, और chruby रूबी के लिए। अब, आइए rbenv को एक स्पिन के लिए ले चलें, क्या हम?

रूबी संस्करण इंस्टॉल करें

हम किसी भी रूबी संस्करण को इंस्टॉल करने के लिए rbenv install कमांड का उपयोग करते हैं:

# रूबी 2.6.1 इंस्टॉल करें $ rbenv install 2.6.1 Downloading openssl-1.1.1i.tar.gz... -> https://dqw8nmjcqpjn7.cloudfront.net/e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242 Installing openssl-1.1.1i... Installed openssl-1.1.1i to /home/directory/.rbenv/versions/2.6.1 Downloading ruby-2.6.1.tar.bz2... -> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.1.tar.bz2 Installing ruby-2.6.1... ruby-build: using readline from homebrew Installed ruby-2.6.1 to /home/directory/.rbenv/versions/2.6.1 # इंस्टॉलेशन जांचें $ rbenv versions # सभी इंस्टॉल किए गए संस्करण दिखाता है। system 2.6.1 # इंस्टॉलेशन के लिए उपलब्ध संस्करण देखें $ rbenv install -L 1.8.5-p52 1.8.5-p113 1.8.5-p114 ... 2.7.0-rc1 2.7.0-rc2 2.7.0 ... truffleruby+graalvm-20.1.0 truffleruby+graalvm-20.2.0 truffleruby+graalvm-20.3.0 # उपरोक्त पूरी सूची लगभग 500 संस्करणों की है, पूरी सूची को स्क्रॉल करना बहुत है। # नीचे दी गई कमांड fzf के साथ आपके विशिष्ट संस्करण को खोजने का एक आसान शॉर्टकट है। $ rbenv install `rbenv install -L | fzf` 

संस्करणों के बीच स्विच करें

रूबी के संस्करणों के बीच स्विच करने की पहचान करने के कई तरीके हैं; अनिवार्य रूप से, rbenv निम्नलिखित करता है:

  • RBENV_VERSION की जांच करता है।
  • स्क्रिप्ट की डायरेक्टरी और उसके पैरेंट में .ruby-version फाइल की खोज करता है जब तक कि यह रूट डायरेक्टरी तक नहीं पहुंच जाता।
  • $PWD और उसके पैरेंट डायरेक्टरीज़ में .ruby-version फाइल की खोज करता है जब तक कि यह रूट डायरेक्टरी तक नहीं पहुंच जाता।
  • ग्लोबल फाइल ~/.rbenv/version का उपयोग करता है।

प्राथमिकता ऊपर से नीचे जाती है। ~/.rbenv/version अंतिम फॉलबैक है और इसे ग्लोबल संस्करण माना जाता है। नीचे देखें:

# पहले प्रोजेक्ट रूट के अंदर # प्रोजेक्ट के लिए रूबी संस्करण चुनें $ touch .ruby-version && echo "2.7.1" >> .ruby-version # चयनित संस्करण सत्यापित करें $ ruby --version ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin20] # परिणाम $ rbenv version 2.7.1 (set by /path/to/current/directory/.ruby-version) # परिणाम # चयनित संस्करण बदलें $ : >> .ruby-version && echo "2.6.1" >> .ruby-version # चयन परिवर्तन सत्यापित करें $ ruby --version ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-darwin20] # परिणाम $ rbenv version 2.6.1 (set by /path/to/current/directory/.ruby-version) # RBENV_VERSION के साथ चयन बदलें जबकि .ruby-version मौजूद है $ export RBENV_VERSION=2.5.1 # चयन परिवर्तन सत्यापित करें # .ruby-version नजरअंदाज किया जाता है। $ ruby --version ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin20] # परिणाम $ rbenv version 2.5.1 (set by RBENV_VERSION environment variable) # परिणाम # किसी ऐसे संस्करण में बदलें जो इंस्टॉल नहीं है और RBENV_VERSION हटाएं $ unset RBENV_VERSION & : >> .ruby-version && echo "2.4.1" >> .ruby-version # चयन परिवर्तन सत्यापित करें $ ruby --version rbenv: version `2.4.1' is not installed (set by full/path/to/current/directory/.ruby-version) # परिणाम 

शिम्स और रीहैशिंग

इन दो अवधारणाओं को rbenv को प्रभावी ढंग से डीबग करने में सक्षम होने के लिए ठीक से समझने की आवश्यकता है।

शिम्स हल्के बैश स्क्रिप्ट्स हैं जो आपके PATH में मौजूद कमांड्स को इंटरसेप्ट करते हैं और उन्हें निष्पादन के लिए उपयुक्त संस्करण पर रूट करते हैं। उच्च स्तर पर, हर कमांड (उदाहरण के लिए, rspec) को rbenv exec rspec में अनुवादित किया जाता है। विवरण नीचे देखें।

सबसे पहले, rbenv सभी कमांड्स (rspec, bundle, आदि) के लिए सभी इंस्टॉल किए गए रूबी संस्करणों में एक शिम बनाता है ताकि CLI को कॉल को इंटरसेप्ट किया जा सके चाहे संस्करण कुछ भी हो। ये शिम्स ~/.rbenv/shims पर पाए जा सकते हैं। प्रत्येक शिम में वही बैश स्क्रिप्ट होती है, जैसा कि नीचे दिखाया गया है:

#!/usr/bin/env bash set -e [ -n "$RBENV_DEBUG" ] && set -x program="${0##*/}" if [ "$program" = "ruby" ]; then for arg; do case "$arg" in -e* | -- ) break ;; */* ) if [ -f "$arg" ]; then export RBENV_DIR="${arg%/*}" break fi ;; esac done fi export RBENV_ROOT="/home/directory/.rbenv" exec "/usr/local/Cellar/rbenv/1.1.2/libexec/rbenv" exec "$program" "$@" 

अगला, ऊपर की स्क्रिप्ट मोटे तौर पर निम्नलिखित में अनुवादित होती है:

  • यदि प्रोग्राम का नाम ruby है और आर्गुमेंट -e के साथ,
    • rbenv exec ruby <args> में अनुवाद करें
  • यदि प्रोग्राम का नाम ruby है और स्क्रिप्ट का पथ है,
    • RBENV_DIR को स्क्रिप्ट की डायरेक्टरी पर सेट करें। यह rbenv को $PWD से पहले स्क्रिप्ट की डायरेक्टरी में .ruby-version खोजने में सक्षम बनाता है। यदि दोनों स्थानों पर .ruby-version निर्दिष्ट है, तो rbenv स्क्रिप्ट की डायरेक्टरी का चयन करता है।
  • यदि प्रोग्राम का नाम रूबी नहीं है,
    • rbenv exec <program-name> <args> में अनुवाद करें।

अंत में, rbenv exec <command-name> <args> RBENV_VERSION एनवायरनमेंट वेरिएबल की जांच करके कमांड को पास करने के लिए सही संस्करण की पहचान करता है। याद रखें, RBENV_VERSION ऊपर परिभाषित एल्गोरिदम द्वारा सेट किया जाता है।

आपके PATH पर शिम्स को प्रीपेंड किया जाना चाहिए; यह सुनिश्चित करता है कि वे आपके रूबी एक्जीक्यूटेबल्स के लिए संपर्क का पहला बिंदु हैं और ठीक से इंटरसेप्ट कर सकते हैं। आपके PATH सेटअप को समझने और यह जानने का सबसे अच्छा तरीका जो मैंने पाया है कि क्या आपके शिम्स ठीक से इंटरसेप्ट कर रहे हैं, वह निम्न है:

$ which -a bundle /path/to/home/.rbenv/shims/bundle /usr/bin/bundle 

which -a bundle: यह सरलता से आपके PATH के माध्यम से देखता है और उस क्रम में प्रिंट करता है जिसमें यह पाया जाता है, वे स्थान जहां bundle पाया जा सकता है। यदि ~/.rbenv/shims में किसी भी चीज़ से पहले कुछ प्रिंट होता है, तो इसका मतलब है कि आपके शिम्स ठीक से सेट अप नहीं हैं। rbenv which bundle यह प्रकट नहीं करेगा क्योंकि कमांड rbenv के संदर्भ में काम करता है न कि आपके PATH को खोजता है।

रीहैशिंग शिम्स बनाने की प्रक्रिया है। जब आप नए इंस्टॉल किए गए रूबी जेम जो एक्जीक्यूटेबल प्रदान करता है, जैसे rspec, तो आपको शिम बनाने के लिए rbenv rehash चलाने की आवश्यकता है ताकि rspec के बाद के कॉल्स को rbenv द्वारा इंटरसेप्ट किया जा सके और उपयुक्त रूबी संस्करण पर पास किया जा सके।

RubyGems

अगला है RubyGems। यह आधिकारिक रूबी साइट से उपलब्ध है। RubyGems एक रूबी पैकेजिंग सिस्टम है जिसे लाइब्रेरीज़ के निर्माण, साझाकरण, और इंस्टॉलेशन की सुविधा के लिए डिज़ाइन किया गया है; कुछ मायनों में, यह apt-get जैसे डिस्ट्रीब्यूशन पैकेजिंग सिस्टम के समान है, लेकिन रूबी सॉफ्टवेयर पर लक्षित है। RubyGems जेम्स साझा करने का वास्तविक तरीका है। वे आमतौर पर ~/.rbenv/versions/{version-number}/lib/ruby/gems/{minor-version}/ पर इंस्टॉल किए जाते हैं, या इसका संस्करण, इस पर निर्भर करता है कि किस वर्जन मैनेजर का उपयोग किया जाता है। रूबी का डिफ़ॉल्ट आवश्यक मेथड Kernel.require जेम्स इंस्टॉलेशन डायरेक्टरी से जेम्स लोड करने के लिए कोई तंत्र प्रदान नहीं करता है। RubyGems Kernel.require को मंकी-पैच करता है ताकि

  • पहले, $LOAD_PATH में जेम्स खोजें।
  • यदि नहीं मिला, तो GEMS INSTALLATION DIRECTORY में जेम्स खोजें।
    • एक बार मिल जाने पर, पथ को $LOAD_PATH में जोड़ें।

यह "नेटिवली" काम करता है क्योंकि रूबी 1.9 संस्करण से डिफ़ॉल्ट रूप से RubyGems के साथ आता है; पिछले रूबी संस्करणों में RubyGems को मैन्युअल रूप से इंस्टॉल करने की आवश्यकता होती थी। हालांकि यह नेटिवली काम करता है, इस अंतर को जानना डीबगिंग के दौरान भी महत्वपूर्ण है।

एक जेम किसी विशिष्ट समस्या को हल करने के लिए उपयोग किए जाने वाले संबंधित कोड का एक समूह है। एक जेम इंस्टॉल करें और जेम एनवायरनमेंट के बारे में जानकारी प्राप्त करें:

$ gem install gemname 
$ gem env RubyGems Environment: - RUBYGEMS VERSION: 3.1.2 - RUBY VERSION: 2.7.1 (2020-03-31 patchlevel 83) [x86_64-darwin20] - INSTALLATION DIRECTORY: /path/to/home/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0 - USER INSTALLATION DIRECTORY: /path/to/home/.gem/ruby/2.7.0 - RUBY EXECUTABLE: /path/to/home/.rbenv/versions/2.7.1/bin/ruby - GIT EXECUTABLE: /usr/bin/git - EXECUTABLE DIRECTORY: /path/to/home/.rbenv/versions/2.7.1/bin - SPEC CACHE DIRECTORY: /path/to/home/.gem/specs - SYSTEM CONFIGURATION DIRECTORY: /path/to/home/.rbenv/versions/2.7.1/etc - RUBYGEMS PLATFORMS: - ruby - x86_64-darwin-20 - GEM PATHS: - /path/to/home/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0 - /path/to/home/.gem/ruby/2.7.0 - GEM CONFIGURATION: ... - REMOTE SOURCES: - https://rubygems.org/ - SHELL PATH: - /path/to/home/.rbenv/versions/2.7.1/bin 

RubyGems इस समस्या को कैसे हल करता है? यह Kernel के require सिस्टम को अपने स्वयं के require मेथड के साथ मंकी पैच करता है। इसके लागू होने के साथ, जब require honeybadger कहा जाता है, तो यह honeybadger.rb के लिए जेम्स फोल्डर के माध्यम से खोजता है और मिलने पर जेम को सक्रिय करता है।

उदाहरण के लिए, require 'honeybadger' निम्नलिखित के समान कुछ उत्पन्न करता है:

  • spec = Gem::Specification.find_by_path('honeybadger')
  • spec.activate

एक जेम को सक्रिय करने का सीधा मतलब है इसे $LOAD_PATH में रखना। RubyGems एक जेम के सभी निर्भरताओं को जेम को डाउनलोड करने से पहले डाउनलोड करने में भी मदद करता है।

साथ ही, Rubygems एक अच्छी सुविधा के साथ आता है जो आपको gem open <gem-name> के साथ संबंधित जेम की डायरेक्टरी खोलने में सक्षम बनाता है; उदाहरण के लिए,

रूबी डिपेंडेंसी मैनेजमेंट में महारत हासिल करना: Rbenv, RubyGems, और Bundler कैसे इंटरैक्ट करते हैं

यह हमें हमारे ऐप द्वारा संदर्भित जेम के विशिष्ट संस्करण को आसानी से खोजने/ट्रेस करने की अनुमति देता है।

Bundler

इस लेयर पर, Bundler हमें अपने सभी प्रोजेक्ट निर्भरताओं को आसानी से निर्दिष्ट करने और वैकल्पिक रूप से प्रत्येक के लिए एक संस्करण निर्दिष्ट करने में मदद करता है। फिर, यह हमारे जेम्स को हल करता है, साथ ही इसे और इसकी निर्भरताओं को इंस्टॉल करता है। प्री-बंडलर वास्तविक दुनिया के एप्लिकेशन बनाने के साथ कई चुनौतियां आईं, जैसे:

  • हमारे एप्लिकेशन्स कई निर्भरताओं के साथ मौजूद हैं, और इन निर्भरताओं की विभिन्न अन्य निर्भरताएं और उनके संबंधित संस्करण हैं। एक जेम का गलत संस्करण इंस्टॉल करना आसानी से हमारे ऐप को तोड़ देगा, और इस समस्या को ठीक करने में बहुत आंसू बहाने पड़ते थे।
  • साथ ही, हमारी दो (2) निर्भरताएं एक ही थर्ड-लेवल डिपेंडेंसी को संदर्भित कर सकती हैं। संगतता ढूंढना एक मुद्दा था, और यदि कोई थी, तो यह एक समस्या थी।
  • जहां एक ही मशीन पर कई एप्लिकेशन्स हैं, विभिन्न निर्भरताओं के साथ, हमारा एप्लिकेशन मशीन पर इंस्टॉल किसी भी जेम्स तक पहुंच सकता है, जो कम से कम विशेषाधिकार के सिद्धांत के खिलाफ जाता है और हमारे एप्लिकेशन को मशीन पर इंस्टॉल सभी जेम्स के संपर्क में लाता है, चाहे वे दुर्भावनापूर्ण हों या नहीं।

Bundler तीनों समस्याओं को हल करता है और निम्न कार्य करके हमारे ऐप निर्भरताओं को प्रबंधित करने का एक समझदार तरीका देता है।

Bundler निर्भरताओं को हल करता है और लॉकफाइल जनरेट करता है:

# Gemfile gem 'httparty' 

यदि हम bundle या bundle install चलाते हैं, तो यह लॉकफाइल जनरेट करेगा:

GEM specs: httparty (0.18.1) mime-types (~> 3.0) multi_xml (>= 0.5.2) mime-types (3.3.1) mime-types-data (~> 3.2015) mime-types-data (3.2020.1104) multi_xml (0.6.0) PLATFORMS ruby DEPENDENCIES httparty BUNDLED WITH 2.1.4 

उपरोक्त से, बंडलर httparty के इंस्टॉल किए जाने वाले संस्करण के साथ-साथ Gemfile.lock में इसकी अपनी निर्भरताओं को जनरेट करता है। यह फाइल हमारे ऐप निर्भरताओं का ब्लूप्रिंट है और इसे वर्जन कंट्रोल में चेक इन किया जाना चाहिए। यह सुनिश्चित करता है कि हमारे प्रोजेक्ट निर्भरताएं एनवायरनमेंट्स (डेवलपमेंट, स्टेजिंग, या प्रोडक्शन) में सुसंगत हैं।

Bundler निर्भरताओं के बीच संगतता को हल करता है

यह httparty के लिए निर्भरताओं को हल करता है इसकी निर्भरताओं के लिए उपयुक्त संस्करण ढूंढकर और उन्हें निर्दिष्ट करके। Bundler जेम्स के बीच निर्भरताओं को हल करने का भी प्रयास करता है। उदाहरण के लिए,

# Gemfile gem 'httparty' # जो gem 'mime-types', '>= 3.0.1, < 4.0.1' पर निर्भर करता है gem 'rest-client' # जो gem 'mime-types', '>= 2.0.1, < 3.0' पर निर्भर करता है 

उपरोक्त उदाहरण मनमाना है और इसके परिणामस्वरूप निम्न जैसी त्रुटि होगी:

Bundler could not find compatible versions for gem "mime-types": In Gemfile: httparty was resolved to 0.18.1, which depends on mime-types ('>= 3.0.1, < 4.0.1') rest-client was resolved to 2.0.4, which depends on mime-types ('>= 2.0.1, < 3.0') 

ऐसा इसलिए है क्योंकि दो जेम्स की निर्भरताएं संगत नहीं हैं और स्वचालित रूप से हल नहीं की जा सकतीं।

Bundler हमारे Gemfile में निर्दिष्ट नहीं लेकिन इंस्टॉल किए गए जेम्स तक पहुंच को प्रतिबंधित करता है

निम्न जैसे सैंपल जेमफाइल में,

# Gemfile gem 'httparty' # irb require 'rest-client' # LoadError उठाता है (cannot load such file -- rest-client) 

यह सुनिश्चित करता है कि केवल हमारे Gemfile में निर्दिष्ट निर्भरताओं को हमारे प्रोजेक्ट द्वारा आवश्यक किया जा सकता है।

Bundle exec

जब आप प्रोजेक्ट डायरेक्टरी में rspec चलाते हैं, तो Gemfile में निर्दिष्ट संस्करण के अलावा किसी अन्य संस्करण को चलाने की संभावना होती है। ऐसा इसलिए है क्योंकि सबसे हालिया संस्करण को Gemfile में निर्दिष्ट संस्करण के बजाय चलाने के लिए चुना जाएगा। bundle exec rspec सुनिश्चित करता है कि rspec उस प्रोजेक्ट के संदर्भ में चलाया जाए (यानी, Gemfile में निर्दिष्ट जेम्स)।

Bundle binstubs

अक्सर, हम लेख पढ़ते हैं जहां हम ./bin/rails जैसी कमांड्स चलाते हैं; यह कमांड bundle exec rails के समान है। बिनस्टब्स bundle exec के उपयोग को आसान बनाने के लिए रूबी एक्जीक्यूटेबल्स के चारों ओर रैपर्स हैं।

बिनस्टब जनरेट करने के लिए, bundle binstubs gem-name का उपयोग करें। यह ./bin फोल्डर में एक बिनस्टब बनाता है लेकिन यदि सेट है तो --path डायरेक्टरी के साथ कॉन्फ़िगर किया जा सकता है।

संदर्भ

अधिक जानने के लिए, इन संदर्भों को देखें:

  • How Do Gems Work?
  • Rbenv
  • RubyGems
  • Bundler

  1. WPS क्या है और यह कैसे काम करता है? WPS क्या है और यह कैसे काम करता है?

    WPS का मतलब है वाई-फाई प्रोटेक्टेड सेटअप (Wi-Fi Protected Setup)। WPS का क्या अर्थ है? WPS घर पर एक सुरक्षित वाई-फाई नेटवर्क सेटअप करने का एक तरीका है जिसमें न्यूनतम प्रयास की आवश्यकता होती है। इसमें आमतौर पर आपके राउटर पर WPS बटन को दबाकर उसे सक्रिय करना शामिल होता है। कई राउटर्स पर WPS बटन को वा

  1. रूबी 2.6 में MJIT को समझना: जस्ट-इन-टाइम कंपाइलर प्रदर्शन को कैसे बढ़ाता है रूबी 2.6 में MJIT को समझना: जस्ट-इन-टाइम कंपाइलर प्रदर्शन को कैसे बढ़ाता है

    रूबी का प्रदर्शन संस्करण दर संस्करण बहुत सुधर रहा है… और रूबी विकास टीम रूबी को और भी तेज़ बनाने के लिए हर संभव प्रयास कर रही है! इन प्रयासों में से एक 3×3 प्रोजेक्ट है। लक्ष्य? रूबी 3.0, रूबी 2.0 से 3 गुना तेज़ होगा। इस प्रोजेक्ट का हिस्सा नया MJIT कंपाइलर है, जो इस लेख का विषय है। MJIT समझाया गया

  1. Windows 10 और Echo डिवाइस पर Cortana और Alexa को इंटीग्रेट करें: चरण-दर-चरण गाइड Windows 10 और Echo डिवाइस पर Cortana और Alexa को इंटीग्रेट करें: चरण-दर-चरण गाइड

    Microsoft ने जनवरी में अपने Build डेवलपर सम्मेलन में घोषणा करने के बाद आखिरकार Alexa को Windows 10 PC और Cortana को Echo स्पीकर पर लाया है। वर्तमान में प्रीव्यू केवल संयुक्त राज्य अमेरिका में उपलब्ध है, लेकिन ऐसा लगता है कि इस साझेदारी का लंबा रास्ता तय करना है। हम एक बहुआयामी दुनिया में रहते हैं ज